There are three different types of "lock-free" algorithms. The definitions given in Concurrency in Action are:
- Obstruction-Free: If all other threads are paused, then any given thread will complete its operation in a bounded number of steps.
- Lock-Free: If multiple threads are operating on a data structure, then after a bounded number of steps one of them will complete its operation.
- Wait-Free: Every thread operating on a data structure will complete its operation in a bounded number of steps, even if other threads are also operating on the data structure.
I asked in a previous question why code using mutexes don't satisfy definition (2) above. The answer is that lock-free algorithms must also be non-blocking.
To be lock-free, the algorithm must be "non-blocking" in addition to one of the three conditions above. An algorithm is called non-blocking if failure or suspension of one thread does not affect failure or suspension of another thread. (Wiki)
This seemed like a satisfactory answer. However, in this talk, Herb Sutter presents what is purportedly a lock-free producer consumer algorithm. Here is my summary of the algorithm:
There are N+1 threads. 1 thread is a producer and N threads are consumers. There is an array of length N visible to all threads. The producer puts tasks in empty entries of the array. The i-th consumer takes out and performs the task in the i-th entry of the array, leaving the entry empty.
Here is my problem: this producer-consumer algorithm fails to be non-blocking. If all of the consumers are suspended, then the array fills up with tasks, and the producer cannot make progress. Herb Sutter addresses the question of whether or not it is lock-free at time stamp 45:19. About the producer, he says:
The threads can get jammed. It may wait if all of the mailboxes are full. It is wait-free up to N active workers (consumers)... Beyond N active workers... so if all the slots are full, then it's no longer wait-free, it's just lock-free. So overall, it is just lock-free.
However, this does not explain why this producer consumer algorithm is non-blocking, which a condition for being lock free.
Is Herb Sutter's producer-consumer algorithm lock-free? Is it non-blocking? How is this consistent with the definition of lock-free I gave: (i) satisfy the non-blocking condition and (ii) satisfy one of (1), (2), or (3) above.
Edit: Below is the portion of the producer's code that contains what I believe to be a "spinlock" at while (slot[curr] != null)
:
curr = 0;
// Phase 1: Build and distribute tasks
while (ThereAreMoreTasks()){
task = AllocateAndBuildNewTask();
while (slot[curr] != null)
curr = (curr + 1)%K;
slot[curr] = task;
sem[curr].signal();
}
// Phase 2
// ...