The committee that standardizes the C programming language (ISO/IEC JTC1/SC22/WG14) has completed a major revision of the C standard. The previous version of the standard, completed in 1999, was colloquially known as "C99." As one might expect, the new revision completed at the very end of last year is known as "C11."

In this article and its companion article, I will describe the major new features of C11 in concurrency, security, and ease of use. A final article will discuss compatibility between C11 and C++.

Concurrency

C11 standardizes the semantics of multithreaded programs, potentially running on multicore platforms, and lightweight inter-thread communication using atomic variables.

The header <threads.h> provides macros, types, and functions to support multi-threading. Here is a summary of the macros, types, and enumeration constants:


Macros: thread_local, ONCE_FLAG, TSS_DTOR_ITERATIONS cnd_t, thrd_t, tss_t, mtx_t, tss_dtor_t, thrd_start_t, once_flag .


. Enumeration constants to pass to: mtx_init: mtx_plain, mtx_recursive, mtx_timed .

.

Enumeration constants for threads: thrd_timedout, thrd_success, thrd_busy, thrd_error, thrd_nomem .

.

Functions for condition variables:

call_once(once_flag *flag, void (*func)(void));

cnd_broadcast(cnd_t *cond);

cnd_destroy(cnd_t *cond);

cnd_init(cnd_t *cond);

cnd_signal(cnd_t *cond);

cnd_timedwait(cnd_t *restrict cond, mtx_t *restrict mtx, const struct timespec *restrict ts);

cnd_wait(cnd_t *cond, mtx_t *mtx);


The mutex functions:

void mtx_destroy(mtx_t *mtx);

int mtx_init(mtx_t *mtx, int type);

int mtx_lock(mtx_t *mtx);

int mtx_timedlock(mtx_t *restrict mtx,

const struct timespec *restrict ts);

int mtx_trylock(mtx_t *mtx);

int mtx_unlock(mtx_t *mtx);

functions:

Thread functions:

int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);

thrd_t thrd_current(void);

int thrd_detach(thrd_t thr);

int thrd_equal(thrd_t thr0, thrd_t thr1);

noreturn void thrd_exit(int res);

int thrd_join(thrd_t thr, int *res);

int thrd_sleep(const struct timespec *duration, struct timespec *remaining);

void thrd_yield(void);


Thread-specific storage functions:

int tss_create(tss_t *key, tss_dtor_t dtor);

void tss_delete(tss_t key);

void *tss_get(tss_t key);

int tss_set(tss_t key, void *val);

These standardized library functions are more likely to be used as a foundation for easier-to-use APIs than as a platform for building applications. (See "When Tasks Replace Objects," by Andrew Binstock, for discussion of higher-level APIs.) For example, when using these low-level library functions it is very easy to create a data race, in which two or more threads write (or write-and-read) to the same location without synchronization. The C (and C++) standards permit any behavior if a data race happens to some variable x , which can lead to serious trouble. For example, some bytes of the value of x might be set by one thread and other bytes could be set by another thread ("torn values"), or some side-effect that appears to take place after assignment to x might (to another thread or another processor) appear to take place before that assignment. Here is a short program