Concurrent Counters
Explore how to make counters thread-safe by adding locks and examine performance implications. Understand scalable approximate counters that use local and global locks to balance accuracy and speed in concurrent updates.
We'll cover the following...
One of the simplest data structures is a counter. It is a structure that is commonly used and has a simple interface. We define a simple non-concurrent counter in the code excerpt below.
Simple but not scalable
As you can see, the non-synchronized counter is a trivial data structure, requiring a tiny amount of code to implement. We now have our next challenge: how can we make this code thread safe? The code excerpt below shows how we do so.
This concurrent counter is simple and works correctly. In fact, it follows a design pattern common to the simplest and most basic concurrent data structures: it simply adds a single lock, which is acquired when calling a routine that manipulates the data structure, and is released when returning from the call. In this manner, it is similar to
At this point, you have a working concurrent data structure. The problem you might have is performance. If your data structure is too slow, you’ll have to do more than just add a single lock; such optimizations, if needed, are thus the topic of the rest of the chapter. Note that if the data structure is not too slow, you are done! No need to do something fancy if something simple will work.
To understand the performance costs of the simple approach, we run a benchmark in which each thread updates a single shared counter a fixed number of times; we ...