Threads (native)
Inititialization by one thread
Section titled “Inititialization by one thread”In most cases all data that is accessed by several threads should be initialized before the threads are created. This ensures that all threads start with a clear state and no race condition occurs.
If this is not possible once_flag and call_once can be used
#include <threads.h>#include <stdlib.h>
// the user data for this exampledouble const* Big = 0;
// the flag to protect big, must be global and/or staticstatic once_flag onceBig = ONCE_INIT;
void destroyBig(void) { free((void*)Big);}
void initBig(void) { // assign to temporary with no const qualification double* b = malloc(largeNum); if (!b) { perror("allocation failed for Big"); exit(EXIT_FAILURE); } // now initialize and store Big initializeBigWithSophisticatedValues(largeNum, b); Big = b; // ensure that the space is freed on exit or quick_exit atexit(destroyBig); at_quick_exit(destroyBig);}
// the user thread function that relies on Bigint myThreadFunc(void* a) { call_once(&onceBig, initBig); // only use Big from here on ... return 0;}The once_flag is used to coordinate different threads that might want to initialize the same data Big. The call to call_once guarantees that
initBigis called exactly oncecall_onceblocks until such a call toinitBighas been made, either by the same or another thread.
Besides allocation, a typical thing to do in such a once-called function is a dynamic initialization of a thread control data structures such as mtx_t or cnd_t that can’t be initialized statically, using mtx_init or cnd_init, respectively.
Start several threads
Section titled “Start several threads”#include <stdio.h>#include <threads.h>#include <stdlib.h>
struct my_thread_data { double factor;};
int my_thread_func(void* a) { struct my_thread_data* d = a; // do something with d printf("we found %g\n", d->factor); // return an success or error code return d->factor > 1.0;}
int main(int argc, char* argv[argc+1]) { unsigned n = 4; if (argc > 1) n = strtoull(argv[1], 0, 0); // reserve space for the arguments for the threads struct my_thread_data D[n]; // can't be initialized for (unsigned i = 0; i < n; ++i) { D[i] = (struct my_thread_data){ .factor = 0.5*i, }; } // reserve space for the ID's of the threads thrd_t id[4]; // launch the threads for (unsigned i = 0; i < n; ++i) { thrd_create(&id[i], my_thread_func, &D[i]); } // Wait that all threads have finished, but throw away their // return values for (unsigned i = 0; i < n; ++i) { thrd_join(id[i], 0); } return EXIT_SUCCESS;}Syntax
Section titled “Syntax”#ifndef __STDC_NO_THREADS__# include <threads.h>#endifvoid call_once(once_flag *flag, void (*func)(void));int cnd_broadcast(cnd_t *cond);void cnd_destroy(cnd_t *cond);int cnd_init(cnd_t *cond);int cnd_signal(cnd_t *cond);int cnd_timedwait(cnd_t *restrict cond, mtx_t *restrict mtx, const struct timespec *restrict ts);int cnd_wait(cnd_t *cond, mtx_t *mtx);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);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);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);
Remarks
Section titled “Remarks”C11 threads are an optional feature. Their absence can be tested with __STDC__NO_THREAD__. Currently (Jul 2016) this feature is not yet implemented by all C libraries that otherwise support C11.