Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / parallel

Solving the Sleeping Barber Problem with the Concurrency Explorer

5.00/5 (1 vote)
27 Jul 2018CPOL14 min read 8.7K  
The Sleeping Barber problem, a classic inter-process communication problem, can be studied and explored more easily using tools such as the Concurrency Explorer than using standard parallel or asynchronous coding techniques.

Introduction

The Concurrency Explorer (ConcX) provides the tools and features to explore and solve a variety of parallel or asynchronous problems, including the Sleeping Barber problem, described by Wikipedia as follows:

“In computer science, the sleeping barber problem is a classic inter-process communication and synchronization problem between multiple operating system processes. The problem is analogous to that of keeping a barber working when there are customers, resting when there are none, and doing so in an orderly manner.

The analogy is based upon a hypothetical barber shop with one barber. The barber has one barber's chair in a cutting room and a waiting room containing a number of chairs in it. When the barber finishes cutting a customer's hair, he dismisses the customer and goes to the waiting room to see if there are others waiting. If there are, he brings one of them back to the chairs and cut their hair. If there are none, he returns to the chair and sleeps in it.

Each customer, when they arrive, looks to see what the barber is doing. If the barber is sleeping, the customer wakes him up and sits in the cutting room chair. If the barber is cutting hair, the customer stays in the waiting room. If there is a free chair in the waiting room, the customer sits in it and waits their turn. If there is no free chair, the customer leaves.”

The Wikipedia article then discusses a variety of concurrency problems, such as:

  • the barber and the newly-arrived customer check each other’s status at the same time so they deadlock because at that moment:

    • The barber sees no one sitting in a chair and thinks the waiting room is empty so goes to sleep

    • The customer thinks the barber is busy so doesn’t try to wake up the barber and just patiently waits for the barber

  • two customers arrive at the same time, see the barber is already busy, and then both try to sit in the same chair, causing either:

    • Both customers to try to occupy the same chair or

    • Both customers fail to get the chair so both customers leave

Other concurrency problems can also occur depending on how well inter-process communications have been defined.  But before you get that far away look in your eyes and start mapping out your code solution in your head, consider using the ConcX to solve the Sleeping Barber problem.

Solving the Sleeping Barber Problem

The Concurrency Explorer (ConcX) is a free, open source tool available from the Avian Computing Project. ConcX is an interactive GUI tool designed to help us think about parallel problems. ConcX encourages us to imagine a parallel problem/program as resembling a flock of birds where each bird behaves (eats, sleeps, etc) and operates independently but also competes and cooperates with the other birds in the flock.

The Customer, Barber, ShopManager and Chair objects are all provided as part of the ConcX download. You could add one or more of each of these objects one by one or you can just load the barbershop20cust.bird file, included in the standard ConcX download. This file will load and configure one barber, one shop manager, and twenty customers.

When the objects are done loading, ConcX will look like the following screenshot:

Image 1

The numbered tabs on the left represent the birds that were loaded and configured to perform the roles of the barber and customers. You can click on the individual tabs to see configuration details of each bird. In the center of the screen is a list of the names and types of the birds next to their individual progress bars. Each time a bird (Barber, Customer, or ShopManager) successfully “eats”, its progress bar will grow. The progress bars are updated in real time so there is no need to wait until a run is completed to see if every thread is working as desired.

Click the Start All button at the bottom left of the screen. The activity progress bars on the right side of the ConcX screen will start to grow in relation to how many times each bird successfully eats (see the following screenshot).

Image 2

Each Customer’s progress bar will only grow while they are actually waiting. Each Customer’s arrival time was pre-configured so they don’t all arrive at the same time. When Customers can’t find a chair, they give up and leave. If a customer waits too long (individually configured), they give up and leave. Customers who successfully get a haircut (or give up) will terminate their thread and their progress bar will stop growing.

Each time the barber gives a haircut, his progress bar will grow; if there is only one customer, the barber’s progress bar will only grow once. Only the shop manager’s progress bar will keep growing throughout the run because he is constantly checking for updates to make to the haircuts reports. When his line stops growing, click on the TupleTree tab (upper right of the screen) to see the results of the run. More about the TupleTree later in this document.

Sleeping Barber Results

The following screenshot shows the contents of the TupleTree after running the standard Sleeping Barber solution. The DailyTransactionPod contains the reports that were generated and continuously updated by the ShopManager.

The reports include:

  • the names of customers who received haircuts and the barber(s) who gave those haircuts

  • The names of customers who couldn’t find chairs or ran out of patience and left. Both represent lost opportunities.

  • A list of haircuts by barber

  • A list of when each customer was called but was absent

Image 3

Note that the Customers are all listed in alphabetical order. That’s because Customer #1 thru Customer #20 were all given names in alphabetical order and arrive in that order. That makes it easy to figure out if the customers do in fact get their haircuts in order of their arrival.

Here’s the full report, copied from the TupleTree screen

Customers Completed Report
       CustName  Arrvd At  Start At  FinishAt  $Paid    BarberName
       Adambb9   17:001    17:060    18:060    $10.00   Zeb
       Bertc4a   17:919    18:075    20:075    $20.00   Zeb
       Chada24   18:937    20:098    23:099    $30.00   Zeb
       Dave9e1   20:954    23:133    24:633    $15.00   Zeb
       Evanb05   22:972    24:662    27:163    $25.00   Zeb
       Greg14f   27:007    27:549    29:550    $20.00   Zeb
       Hanka66   27:026    29:605    32:606    $30.00   Zeb
       Ivan42a   27:045    32:631    34:132    $15.00   Zeb
       Jake3da   31:060    34:167    36:668    $25.00   Zeb
       Kentbd3   33:077    36:679    37:680    $10.00   Zeb
       Lukebe8   34:096    37:746    39:747    $20.00   Zeb
       Mark2f9   36:113    39:756    42:756    $30.00   Zeb
       Natef97   37:131    42:764    44:265    $15.00   Zeb
       Otto7d3   39:149    44:302    46:803    $25.00   Zeb
       Todde18   42:233    48:249    50:750    $25.00   Zeb
       -----------------------------------------------

Customers Who Gave Up or Couldn't Find a Chair
       CustName   Arrvd At   Gave Up At
       Fredc86    23:089     26:100    
       Petec74    39:170     39:170    
       Quin77b    39:189     39:189    
       Rami325    39:207     39:207    
       Stan621    39:226     39:226    
       -----------------------------------------------

Barber Productivity Report
       Barber Name   Haircut Amt    Haircut Time
       Zeb           $10.0          10  minutes
       Zeb           $20.0          20  minutes
       Zeb           $30.0          30  minutes
       Zeb           $15.0          15  minutes
       Zeb           $25.0          25  minutes
       Zeb           $20.0          20  minutes
       Zeb           $30.0          30  minutes
       Zeb           $15.0          15  minutes
       Zeb           $25.0          25  minutes
       Zeb           $10.0          10  minutes
       Zeb           $20.0          20  minutes
       Zeb           $30.0          30  minutes
       Zeb           $15.0          15  minutes
       Zeb           $25.0          25  minutes
       Zeb           $25.0          25  minutes
       -----------------------------------------------

Barber Called Absent Customer Report
       Barber Name  Cust Name  Called At
       Zeb          Fredc86    27:534
       Zeb          Petec74    47:166
       Zeb          Quin77b    47:482
       Zeb          Rami325    47:841
       Zeb          Stan621    48:202
       -----------------------------------------------

Note that there were 5 customers who gave up waiting (1 waited too long and 4 couldn’t find a chair). The report shows that Fred waited for about 3 seconds before giving up, which matches his patience setting of 3 seconds. The other 4 customers have arrival times and departure times that are nearly identical, which indicates that they all left because they couldn’t find a chair. Since the Arrival Time for Otto, Pete, Quin, Rami, and Stan are within 80 milliseconds of each other, it shows that they all came in as a group but only Otto found a chair and got a haircut.

Let’s see how making a few changes affects the results.

Exploring Sleeping Barber Possibilities

The following screenshot shows that tab #1 (Mr Smith, the Shop Manager) has been selected and that his Externally Managed Variable (XMV) tab has also been selected. The “Chairs in Waiting Room” field was blank, meaning that the ShopManager put out the default number of chairs (3). By updating the XMV field to 5 we can rerun the simulation to see if adding more chairs fixes the problem. No re-compiling required.

Image 4

Click the “Clear All Activities” button in the bottom right corner and then click the Start All button in the bottom left corner of the screen.

The following report excerpt shows just the customers who gave up:

Customers Who Gave Up or Couldn't Find a Chair
       CustName   Arrvd At   Gave Up At
       Fredbd3    39:798     42:904   
       Rami226    55:812     55:812   
       Stan7f5    55:819     55:819   
       -----------------------------------------------

 

<meta charset="utf-8" />

Now only three customers gave up: Impatient Fred and the last two in the group of five who came in together. If we add a couple more chairs, clear the results and then rerun the simulation, the Customer Gave Up portion of the report will contain only Impatient Fred.

But what if the barbershop is small and doesn’t have room for 7 chairs? It would be pretty expensive to expand the shop for just those rare occasions when 5 or more customers arrive all at once. Let’s see what happens if we add a second barber instead of adding more chairs.

First, click on tab #1 and blank out/zero out Mr Smith’s Chairs in Waiting Room value.

Next, click the Add New Bird button (bottom center of the screen)  and add a new Barber bird as follows:

Click on Add New Bird button and then

  • (Bird) Type: type “bar” in the Type field and press Tab. ConcX will find multiple bird types that begin with “bar” and will pop up a ComboBox populated with all matching items. If not already highlighted, select the Barber.class and click on the OK button.

  • Food Eaten: type “bar” in the Food Type field and press Tab. ConcX will find multiple food pods that begin with “bar” and will pop up a ComboBox populated with all matching items. If not already highlighted, select the BarberBacklogPod and click on the OK button.

  • Food Stored: type “null” in the Food Type field and press Tab. ConcX will find only one matching food pod and fill in the full name of NullPod

  • Give the Barber an appropriately casual name, such as Yank or Willy

  • Click on the Barber’s Vitality tab and change his Stamina to a negative number, such as -5000. Negative numbers prevent a bird from dying if it goes too long without eating.

Click the Clear All Activities button and then Click the Start All button.

When the run is finished, the Shop Manager’s results will be similar to the following:

Customers Completed Report
       CustName  Arrvd At  Start At  FinishAt  $Paid    BarberName
       Adam81e   57:134    57:136    58:136    $10.00   Zeb
       Bertfaa   58:050    58:084    00:085    $20.00   Yank
       Chad422   59:067    59:079    02:079    $30.00   Zeb
       Dave5a8   01:085    01:121    02:620    $15.00   Yank
       Evan447   03:102    03:108    05:608    $25.00   Zeb
       Freda5f   05:118    05:137    06:137    $10.00   Yank
       Greg4a4   07:135    07:142    09:142    $20.00   Zeb
       Hankac2   07:153    07:191    10:191    $30.00   Yank
       Ivan8fe   07:171    09:171    10:672    $15.00   Zeb
       Jake753   11:185    11:240    13:740    $25.00   Yank
       Kent3a6   13:203    13:235    14:235    $10.00   Zeb
       Luke0cb   14:219    14:233    16:233    $20.00   Yank
       Nate4cf   17:253    17:275    18:775    $15.00   Zeb
       Mark0b8   16:236    16:252    19:253    $30.00   Yank
       Petedb7   19:290    19:321    20:321    $10.00   Yank
       Otto736   19:272    19:299    21:798    $25.00   Zeb
       Quin94d   19:309    20:330    22:330    $20.00   Yank
       Toddee5   22:354    22:371    24:870    $25.00   Yank
       -----------------------------------------------

Customers Who Gave Up or Couldn't Find a Chair
       CustName   Arrvd At   Gave Up At
       Ramif1e    19:327     19:327    
       Standec    19:346     19:346    
       -----------------------------------------------

Barber Productivity Report
       Barber Name   Haircut Amt    Haircut Time
       Zeb           $10.0          10  minutes
       Yank          $20.0          20  minutes
       Zeb           $30.0          30  minutes
       Yank          $15.0          15  minutes
       Zeb           $25.0          25  minutes
       Yank          $10.0          10  minutes
       Zeb           $20.0          20  minutes
       Yank          $30.0          30  minutes
       Zeb           $15.0          15  minutes
       Yank          $25.0          25  minutes
       Zeb           $10.0          10  minutes
       Yank          $20.0          20  minutes
       Zeb           $15.0          15  minutes
       Yank          $30.0          30  minutes
       Yank          $10.0          10  minutes
       Zeb           $25.0          25  minutes
       Yank          $20.0          20  minutes
       Yank          $25.0          25  minutes
       -----------------------------------------------

Barber Called Absent Customer
       Barber Name  Cust Name  Called At
       Zeb          Ramif1e    22:124
       Zeb          Standec    22:457
       -----------------------------------------------

 

<meta charset="utf-8" />

A couple of things to note in these results:

  • With two barbers, Impatient Fred got his haircut because he didn’t have to wait too long

  • Just two customers gave up because they couldn’t find a chair

  • The Completed Customers Report lists customers in order of their haircut's completion and not in the order of arrival. This demonstrates that the barbers are working together but asynchronously; one barber never has to wait for the other barber to finish but always goes on to the customer who has been waiting longest.

  • The Shop Manager knows which barber performed which haircuts without having to reprogram anything.

Let’s add a third barber and see what happens. Click the Add New Bird button and add another barber bird as described above. Now click the Clear All Activities button and then the Start All button.

After re-running the simulation, we get the following results:

Customers Who Gave Up or Couldn't Find a Chair
       CustName   Arrvd At   Gave Up At
       Ramibea    11:000     11:000    
       Stanf61    11:018     11:018    
       -----------------------------------------------

<meta charset="utf-8" />This result shows that adding a third barber didn’t help; the same two customers still could not find a chair. So let’s fire the third barber (disable his thread by changing his Type to Not Found) and changing the number of chairs in the waiting room to 4. Now when we Clear All Activities and Start All, every one of the 20 customers is able to get a haircut.

Which means that we've been able to identify two different ways that every customer could be served:

  • by increasing the number of waiting room chairs to 7
  • by adding a second barber and also increasing the number of waiting room chairs to 4

 

<meta charset="utf-8" />

ConcX Concepts

Let's take a look at the foundational concepts of ConcX. Using the ideas in Avian Computing, ConcX maps the various thread states into the natural behaviors of a bird, such as hatching (thread.start), napping (thread.sleep), death (thread.stop) and so on to make it  easier to think about and describe each thread’s actions. Each bird follows a standard life cycle; once they are hatched, they look for food, digest it if they find their type of food, store any resulting foods (the way some birds will hide leftover food), and then take a nap. When the birds get too old or can’t get enough to eat, they die. Expressing the threads’ actions in natural terms is done to make it easier and more natural to think about the threads.

 

<meta charset="utf-8" />

Each “bird” (thread) in ConcX eats one type of food pod and stores one type of food pod in the “TupleTree”. The TupleTree in ConcX is a simplified version of a tuplespace, a concept originally developed for the Linda coordination language. A tuplespace is shared associative memory used as a repository for tuples of data. Linda was originated in 1986 by Sudhir Ahuja, David Gelernter, Nicholas Carriero and others. Linda was the foundation for several major products, including Sun’s JavaSpaces, IBM’s TSpaces, and many more in a variety of languages.

In ConcX, the TupleTree is a singleton that shares data with all the birds using synchronized methods. Any object in the TupleTree can be retrieved by any bird that knows to ask for that type of object. Because the TupleTree manages its objects using synchronized methods, there is never a need for users to create or code mutexes or locks or any other mechanisms for concurrent objects to sharing objects. Instead, the TupleTree manages all sharing of data so you can concentrate on what needs to be done with the data.

The traditional concurrency tools of wait and notify are like a traditional phone system; if the person on the other end of the phone is available when you call them, it works great. Unfortunately if both parties aren’t available at the same time, nothing can happen.

Linda is more like an email system, where the senders and receivers check for and respond to emails at their convenience instead of interrupting each other. In ConcX, the TupleTree is like an email server except it holds food pods that function as shared resources. In this way, Linda provides a safe, simple and robust mechanism for data sharing between multiple asynchronous threads.

Runtime Information in ConcX

One of the original goals of ConcX was to provide ready access to its runtime context, of what was happening to each thread while each one was running. To do this, ConcX provides more information than real-time updating of progress bars. ConcX automatically documents each run several ways, including:

  • Each food pod in the TupleTree has a complete time-stamped history of all events that occured to that individual food pod and which bird caused the event

  • Each bird maintains its own time-stamped history of its events, such as when it looked for food, what food it found, when it digested and stored its food, and so on.

The following excerpts will help to illustrate how the recorded information can be used. First, from the Chair-2 food pod left in the TupleTree at the end of the run, we can see when Bert sat in the chair (every customer who sat in Chair-2 on that run are also documented):

11:14:23:853,WaitingRoomChairPod,Bert78b found a chair in waiting room
11:14:24:127,WaitingRoomChairPod,Bert78b gave up chair to get haircut

 

<meta charset="utf-8" />

Next, here’s an excerpt from the personal history of Customer #2, Bert, available on his History tab:

11:14:23:853,Bert,Bert78b found a chair in waiting room
11:14:23:853,Bert,Created CustInfoFindByNamePod,Bert78b
11:14:23:853,Bert,Created BarberBacklogPod,Bert78b
11:14:23:853,Bert,Looking for food,
11:14:23:853,Bert,eating foodType,Bert78b
11:14:23:853,Bert,Napping,107ms
11:14:23:961,Bert,Looking for food,
11:14:23:961,Bert,eating foodType,Bert78b
11:14:23:961,Bert,Napping,166ms
11:14:24:127,Bert,Looking for food,
11:14:24:127,Bert,eating foodType,Bert78b
11:14:24:127,Bert,bird lifetime was set to 40300 millis
11:14:24:127,Bert,haircut in process

 

<meta charset="utf-8" />

Bert’s History shows that he found an empty chair (Chair #2) at 23:853. After waiting (Looking for food and napping) for about 250 milliseconds, Bert recorded that his haircut was in process at 24:127.

And to cross-check the information, the barber’s (Zeb) History shows that he was sleeping at 23:963, then got the next name from the waiting list (BarberBacklogPod) and then called him (Bert). There’s a short time lag (from 23:995 until 24:127) while Bert takes a 166ms nap but then the desired haircut (2000ms) is given (from 23:995 until 25:996).

11:14:23:963,Zeb,Napping,32ms
11:14:23:995,Zeb,Looking for food,
11:14:23:995,Zeb,Got 1 pods from TupleTree
11:14:23:995,Zeb,eating foodType,barbershop\BarberBacklogPod,Zeb
11:14:23:995,Zeb,Called Bert78b for haircut
11:14:23:995,Zeb,BEFORE Haircut retrieved Bert78b info on attempt 0
11:14:25:996,Zeb,AFTER Haircut retrieved Bert78b info on attempt 0
11:14:25:996,Zeb,ATE_FOOD1-->strFood1 NullPod,STORE_ONE by,barbershop\Barber
11:14:25:996,Zeb,Napping,49ms

While the excerpts shown above only confirm that the barbershop ran as expected, the combined histories of food pods and birds is most useful when things don't go as planned. The time-stamped history entries make it possible to reconstruct the runtime context, down to the state of each thread, when errors were encountered. 

 

<meta charset="utf-8" />

Sleeping Barber Conclusions

The ConcX solution to the Sleeping Barber problem is significantly more complicated than the original problem described in Wikipedia, allowing multiple barbers, shop managers maintaining near real-time reports, impatient customers and more. It is also easier to run and to modify than most other solutions while providing better assurance that it did what it was supposed to do. The ConcX solution is also robust when it is scaled up; the screenshot below shows what happens when the barbershop flock file is loaded five times and then run. All 5 barbers and all 5 shop managers and all 100 customers just work as expected.

Image 5

This article demonstrated some of the strengths of ConcX at exploring concurrent program solutions, including:

  • GUI environment for configuring and running multiple concurrent threads

  • Adding new threads as needed

  • Starting and stopping of individual threads or all threads at any time during a run

  • Simple modification of individual thread settings to help identify which settings are critical and which are unimportant

  • Real-time updating of the progress of every thread on GUI screen for immediate visual feedback for users

  • Timestamped event history of shared data objects, including which bird (thread) possessed the data object

  • Timestamped event history for every bird (thread) for every run with selectable levels of detail for each bird

ConcX was designed to support quick and easy modifications in a robust high-feedback environment to promote the exploration of concurrent programs. ConcX is a free open-source tool designed to promote higher level thinking about concurrent programs; ConcX lets us think about what we want the threads to do instead of thinking about how to code what we want them to do.

History

July 27, 2018: Initial publication of document

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)