All the communication between the Entrance
objects takes place through the single Count object. When the user pressesAs this program runs, you will see the total count and the count at each entrance displayed as people walk through a turnstile. If you comment out the Guard
object in Count::increment( ), you’ll notice that the total number of people is not what you expect it to be. The number of people counted by each turnstile will be different from the value in count. As long as the Mutex is there to synchronize access to the Counter, things work correctly. Keep in mind that Count::increment( ) exaggerates the potential for failure by using temp and yield( ). In real threading problems, the possibility for failure may be statistically small, so you can easily fall into the trap of believing that things are working correctly. Just as in the example above, there are likely to be hidden problems that haven’t occurred to you, so be exceptionally diligent when reviewing concurrent code.Atomic operations
Note that Count::value( )
returns the value of count using a Guard object for synchronization. This brings up an interesting point, because this code willThe problem is that the C++ standard doesn’t guarantee atomicity for any of these operations. Although operations such as returning an int
and incrementing an int are almost certainly atomic on most machines, there’s no guarantee. And because there’s no guarantee, you have to assume the worst. Sometimes you might investigate the atomicity behavior on a particular machine (usually by looking at assembly language) and write code based on those assumptions. That’s always dangerous and ill-advised. It’s too easy for that information to be lost or hidden, and the next person that comes along may assume that this code can be ported to another machine and then go mad tracking down the occasional glitch caused by thread collisions.