Skip to content

Home‎ > ‎Lockfree Algorithms‎ > ‎Introduction

NOTE:

1、wait-free > Lock-free > obstruction-free

I bet you had heard terms like "lockfree" and "waitfree". So what it's all about? Let's start with some definitions.

Wait-freedom

Wait-freedom means that each thread moves forward regardless of external factors like contention from other threads, other thread blocking. Each operations is executed in a bounded number of steps. It's the strongest guarantee for synchronization algorithms. Wait-free algorithms usually use such primitives as atomic_exchange,

atomic_fetch_add (InterlockedExchange, InterlockedIncrement, InterlockedExchangeAdd, __sync_fetch_and_add),

and they do not contain cycles that can be affected by other threads. atomic_compare_exchange primitive (InterlockedCompareExchange, __sync_val_compare_and_swap) is usually not used, because it is usually tied with a "repeat until succeed" cycle.

NOTE:

上述cycle是什么含义?参见下面的**Lock-freedom**章节中给出的例子;

上面这段话 + 下面的两个例子,我们可以看出如下对应关系:

Below is an example of a wait-free algorithm:

void increment_reference_counter(rc_base* obj)
{
    atomic_increment(obj->rc);
}

void decrement_reference_counter(rc_base* obj)
{
    if (0 == atomic_decrement(obj->rc))
        delete obj;
} 

NOTE: 参见:

1、atomic_increment: std::atomic_fetch_add

Each thread is able to execute the function in a bounded number of steps regardless of any external factors.

Lock-freedom

Lock-freedom means that a system as a whole moves forward regardless of anything. Forward progress for each individual thread is not guaranteed (that is, individual threads can starve). It's a weaker guarantee than wait-freedom. Lockfree algorithms usually use atomic_compare_exchange primitive (InterlockedCompareExchange, __sync_val_compare_and_swap).

An example of a lockfree algorithm is:

void stack_push(stack* s, node* n)
{
    node* head;
    do
    {
        head = s->head;
        n->next = head;
    }
    while ( ! atomic_compare_exchange(s->head, head, n));
} 

NOTE: 参见:

1、cppreference std::atomic_compare_exchange_strong

上述过程让我想到了busy-waiting、CAS

As can be seen, a thread can "whirl"(回旋) in the cycle theoretically infinitely. But every repeat of the cycle means that some other thread had made forward progress (that is, successfully pushed a node to the stack). A blocked/interrupted/terminated thread can not prevent(阻止) forward progress of other threads. Consequently, the system as a whole undoubtedly makes forward progress.

Obstruction-freedom

NOTE: "Obstruction"的意思是: 阻碍

Obstruction-freedom guarantee means that a thread makes forward progress only if it does not encounter contention from other threads. That is, two threads can prevent each other's progress and lead to a livelock. It's even weaker guarantee than loсk-freedom. This guarantee may look a bit strange at first. However, note that

(1) blocked/interrupted/terminated threads can not prevent progress of other threads, and

(2) obstruction-free algorithms can be faster than lockfree algorithms.

I am unable to come up with a single example, so I refer you to the original paper Obstruction-Free Synchronization: Double-Ended Queues as an Example.

Termination-safety

Waitfree, lockfree and obstruction-free algorithms provide a guarantee of termination-safety. That is, a terminated thread does not prevent system-wide forward progress.

NOTE: 它们能够保证当thread terminate的时候,system-wide forward progress不会被他阻止