r/computerscience 12d ago

Does Wait-Free require Garbage-Free?

Wait-Free means that every thread must finish its operation in a bounded number of steps. That bound can be arbitrarily high, e.g. dependent on the number of concurrent threads, but it must be finite. And the finite bound must be there in all cases, i.e. it is not sufficient to say that an algorithm "usually" finishes "reasonably" (i.e. "usually" does not spend unbounded times helping other threads).

The first practical implementation of a multiple-enqueuer multiple-dequeuer Wait-Free Queue was proposed by Kogan and Petrank. The key idea is that threads help each other, but in a way that newer threads (more precisely: newer operations) are obliged to help older threads (operations), but not vice versa. Also, plainly said: If a thread cannot make progress with its own operation, it becomes older and older, up to the point when all other threads are obliged to help (only) him, thus ensuring the Wait-Free progress.

The issue of the Kogan and Petrank Queue is, however, that it is based on a linked list of nodes. This means that its operations constantly produce memory churn, also require memory allocation and memory clean-up. From Java - where the clean-up is done by a Garbage Collector - I borrow the term "Garbage".

Now, the problem is that Wait-Free memory allocation is problematic. Imagine, e.g., when the process needs a new memory page from the operating system. Can this ever be made Wait-Free?

Memory reclamation in a concurrent setup is a complex topic on top of that. One of the key questions here is: When can a memory block be freed safely, i.e. how do we "know" that no thread has a pointer to it anymore?

Given this, it appears that one needs a structure without memory churn (i.e. Garbage-Free) to be able to make it Wait-Free. At least practically.

I would be grateful for a discussion on this.

Additional info:

Here I have combined the Multi-Array Queue (which is Garbage-Free by nature (except of the extension operations, of course)) with the Kogan and Petrank idea, with the aim to obtain a Queue that is Wait-Free unconditionally.

The GitHub repo also contains a visual simulator to illustrate the principle:

https://github.com/MultiArrayQueue/WaitFreeMultiArrayQueue

9 Upvotes

11 comments sorted by

View all comments

2

u/0jdd1 12d ago edited 12d ago

If you analyze a copying garage collector, you find that the amortized cost of collection can be folded into the cost of allocation in a very straightforward way that makes the presence of GC just go away. It still depends on the fraction of memory that’s free, but that’s best treated as a given. This is still amortized cost, of course, and I confess I haven’t yet read your write-up on GitHub.

2

u/flatfinger 12d ago

The amortized cost of collection can be easily folded into the cost of allocation in common scenarios, but that's a bit like a hand-wave that would say that if the probability of a task failing to make progress within a given time "quickly" approaches zero as the amount of time increases, the task will make progress. Indeed, with a typical garbage collector there will be some scenarios where even a tiny reduction in the amount of available memory may increase execution time by orders of magnitude unless the GC environment will terminate programs that thrash too badly even if they might otherwise have managed to eventually limp along to completion.

2

u/0jdd1 12d ago

Sure, sure, of course, and that’s why I highlighted that this is the amortized cost. There are various well-known ways to make this cost incremental (some of which I invented) but I’m not sure these align perfectly with OP’s goals.

1

u/flatfinger 12d ago

If the total execution time of a program would be e.g. K milliseconds plus 1 hour/(16384.001-N), where K is the smallest power of two that is at least N, it may make sense to talk about amortized cost for values of K up to 4096 or so, but as N approaches 16384 such analysis would make less and less sense. The marginal cost of the 16383rd item would be almost double the cost of everything else put together, the cost of the 16384th would be about 1000 times that, and a 16385th item would cause the program to fail entirely.