C Language
Threads (natifs)
Recherche…
Syntaxe
-
#ifndef __STDC_NO_THREADS__
-
# include <threads.h>
-
#endif
-
void 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);
Remarques
Les threads C11 sont une fonctionnalité facultative. Leur absence peut être testée avec __STDC__NO_THREAD__
. Actuellement (juillet 2016), cette fonctionnalité n'est pas encore implémentée par toutes les bibliothèques C qui prennent en charge C11.
Les bibliothèques C connues pour prendre en charge les threads C11 sont les suivantes:
C bibliothèques qui ne supportent pas les threads C11, pourtant:
Commencer plusieurs discussions
#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;
}
Initialisation par un thread
Dans la plupart des cas, toutes les données accessibles par plusieurs threads doivent être initialisées avant la création des threads. Cela garantit que tous les threads commencent avec un état clair et qu'aucune condition de concurrence ne se produit.
Si cela n'est pas possible, once_flag
et call_once
peuvent être utilisés
#include <threads.h>
#include <stdlib.h>
// the user data for this example
double const* Big = 0;
// the flag to protect big, must be global and/or static
static 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 Big
int myThreadFunc(void* a) {
call_once(&onceBig, initBig);
// only use Big from here on
...
return 0;
}
once_flag
est utilisé pour coordonner différents threads qui pourraient vouloir initialiser les mêmes données Big
. L'appel à call_once
garantit que
-
initBig
est appelé exactement une fois -
call_once
bloque jusqu'à ce qu'un tel appel àinitBig
ait été effectué, soit par le même thread, soit par un autre.
Outre l'allocation, une fonction typique d'une fonction appelée une fois est une initialisation dynamique d'une structure de données de contrôle de thread telle que mtx_t
ou cnd_t
qui ne peuvent pas être initialisées statiquement, en utilisant mtx_init
ou cnd_init
, respectivement.