C11 Features on Concurrency
C11 Overview
C11 is an informal name for ISO/IEC 9899:2011. It includes multi-thread support, which enables us to use higher-level programming types to deal with concurrency. Now, let's see how to use the C11 features to design a lock-free data structure.
C11 Atomic Types
C11 defines a new _Atomic type specifier. Include the header with #include<stdatomic.h> when you are going to use the atomic type in your program.
The atomic declaration syntax is like _Atomic(type_name) or _Atomic type_name. For example, we could define an atomic integer like this:
_Atomic(int) a; // or
_Atomic int b; // both of them are the atomic integerNotice that the type_name can not be an array or a function; and with the first syntax, it can not be an atomic type, or a qualified type. Refer to here for more information.
We could make a user-defined struct atomic, so that every element inside struct wil be manipulated atomically.
struct Node
{
int data;
struct Node *next;
};
_Atomic struct Node s; // s is also an atomic typeIn addition to make user-defined type atomic, the _Atomic keyword makes it possible to use objects of all atomic types in nearly all the same expressions and contexts as their non-atomic counterparts.
_Atomic int a = 3; // initialize like a normal int type
a = a + 2; // you can perform the atomic addition like thisHere is a simple example of using C11 atomic type:
In order to compile C11 program, we need GCC 4.9 or later. We should specify the parameter to tell the gcc compiler that we would like to compile the program by using C11 standard. Use the following commands to check the GCC version and compile the program:
One of the possible outputs is:
Atomic operations
C11 provides some functions for us to change the content of atomic types like a user-defined struct in an atomic way. Here We will introduce the CAS function, which we will use in lock-free data-struct design.
Description: Atomically, compares the value pointed to by object for equality with that in expected, and if true, replaces the value pointed to by object with desired, and if false, updates the value in expected with the value pointed to by object. (Here, A is the atomic type, while the C is the non-atomic counterpart of A. For example, if A is _Atomic int, then, C is int).
The volatile is a type qualifier like const, and is a property of the type. It indicates that a value may change between accesses (e.g. shared variable in multi-thread program), even if it does not appear to have been modified.
With the volatile keyword, the compiler knows a variable needs to be reread from memory upon each access. It prevents the compiler from performing optimization on code. For more information, please refer to this link.
atmoic_compare_exchange_weak() returns the result of the comparison, either true or false. Here, we use this function to implement a simple lock.
One of the possible outputs is:
For more information, please refer to http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
Last updated
Was this helpful?