-
Notifications
You must be signed in to change notification settings - Fork 16
/
thread.txt
483 lines (422 loc) · 29.1 KB
/
thread.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
THREAD
LINKING ==> #-lboost_thread ou -lboost_thread-mt
EXCEPTIONS ==> # - thread_resource_error : THREAD( ... ),
# this_thread::get_id(), this_thred::at_thread_exit()
# *mutex.*lock() (pas *unlock()), call_once(),
# BARRIER(...), BARRIER.wait()
# - thread_interrupted : un des interruption points
# - std::bad_alloc : this_thread::at_thread_exit()
POLLING VS INTERRUPTS #boost::thread utilise des IRQ pour signaler les
==> #changements (thread achevé, mutex released, condition
#variable, barrier joined, etc.) : il vaut donc mieux
#utiliser boost::thread qu'essayer de l'implémenter
#soi-même, par exemple avec un polling sur des
#variables globales.
HEADERS ==> # - <boost/thread/thread.hpp> : thread, thread_group
# - <boost/thread/mutex.hpp> : mutex, timed_mutex
# - <boost/thread/recursive_mutex> : recursive_*mutex
# - <boost/thread/shared_mutex> : shared_mutex
# - <boost/thread/locks.hpp> : *lock*
# - <boost/thread/barrier.hpp> : barrier
# - <boost/thread/once.hpp> : call_once
# - <boost/thread/condition_variable.hpp> : condition_variable*
# - <boost/thread/thread_time.hpp> : get_system_time
thread #Désigne un thread, associé ou non à un functor.
#Un seul boost::thread peut être associé à une exécution
#de thread donnée.
#thread n'est pas copiable (ni CopyConstructible, ni
#Assignable), mais movable via boost::move.
#Attention : tous les threads s'interrompent (même ceux
#détachés) si le main() se termine : il faut donc faire
#join().
THREAD() #Instantie un THREAD associé à aucun functor (ne lance
#donc rien).
THREAD(FUNCTOR #Instantie un THREAD associé à un thread étant
[, ARGS...]) #l'exécution de FUNCTOR. Ce dernier peut avoir jusqu'à
#9 arguments ARGS.
#Une fois que le thread sera terminé, THREAD ne sera
#plus associé à aucun thread.
#thread_resource_error est lancé en cas d'erreur.
#FUNCTOR et ARGS doivent être copiables : on peut faire
#boost::ref(FUNCTOR) ou boost::ref(ARG) si l'on veut le
#passer par référence (mais FUNCTOR ne doit pas avoir
#une lifetime inférieure à THREAD)
THREAD(boost::move #Instantie un THREAD en lui associant le thread détenu
(THREAD2)) #par THREAD2, ce dernier n'étant plus alors associé à
#aucun thread.
THREAD = boost::move #Même effet que le constructor THREAD(THREAD2)
(THREAD2)
~THREAD #Si THREAD est détruit, le thread auquel il est associé
#est détaché via detach(), et donc ne s'interrompt pas.
THREAD.join() #Ne fait rien si THREAD n'est pas associé à un thread.
#Sinon, attend que le thread de THREAD s'achève.
THREAD.timed_join #
(POSIX_TIME::PTIME)
THREAD.timed_join #Même chose, sauf que la fonction s'achève également après une durée de POSIX_TIME::TIME_DURATION ou
(POSIX_TIME:: #une fois que POSIX_TIME::PTIME est atteint.
TIME_DURATION) #On peut appeler get_system_time(), renvoyant la PTIME courante.
THREAD.detach() #Détache le thread de THREAD, ce dernier n'ayant plus
#de thread associé, et ce premier continuant son
#exécution, sans être lié à un THREAD.
THREAD.interrupt() #Fait qu'au prochain interrupt point rencontré par le
#thread de THREAD, le thread lance une exception
#thread_interrupted et donc s'interrompt. Les interrupt
#points sont :
# - this_thread::interruption_point()
# - this_thread::sleep()
# - THREAD.sleep()
# - THREAD.[timed_]join()
# - CONDITION_VARIABLE[_ANY].[timed_]wait()
THREAD.sleep #
(POSIX_TIME::PTIME) #Interrompt THREAD jusqu'à PTIME.
THREAD.yield() #Donne la main aux autres threads en abandonnant la
#time slice courante impartie.
THREAD.joinable() #Renvoie true si THREAD est associé à un thread.
THREAD.get_id() #Renvoie le THREAD::ID de THREAD.
THREAD == THREAD2
THREAD != THREAD2 #Test d'égalité des THREAD::ID.
THREAD.swap(THREAD2) #
swap(THREAD, THREAD2) #Echange les threads détenus par THREAD et THREAD2
THREAD. #Renvoie le nombre de threads pouvant tourner en même
hardware_concurrency() #temps sur le système actuel (soit le nombre de coeur
#du CPU), sous forme d'UINT_VAL.
this_thread::get_id() #Renvoie le THREAD::ID du THREAD courant. Lance une
#exception thread_resource_error en cas d'erreur.
this_thread:: #Exit handler, mais ne marche qu'en cas de return, pas
at_thread_exit(FUNCTOR) #d'exit(), abort() ou autre, mais oui en cas de
#thread_interrupted exception.
#C'est pour le thread courant.
#Des exceptions std::bad_alloc ou thread_resource_error
#sont lancées si erreur.
this_thread::sleep
(POSIX_TIME:: #Interrompt le thread courant pendant une durée de
TIME_DURATION) #POSIX_TIME::TIME_DURATION
this_thread::
sleep(POSIX_TIME::PTIME)#Interrompt le thread courant jusqu'à PTIME.
this_thread::yield() #Cf plus haut.
this_thread:: #Ne fait rien, mais peut servir d'interruption point si
interruption_point() #interrupt() a été appelé sur le THREAD courant.
this_thread:: #Renvoie true si interrupt() a été appelé sur le THREAD
interruption_requested()#courant.
this_thread:: #Classe qui, une fois instantiée, bloque les tentatives
disable_interruption #d'interrupt() sur le THREAD() courant, jusqu'à sa
#destruction (peut donc être dans un bloc { } limitant
#sa lifetime).
this_thread:: #Classe qui, une fois instantiée, bloque l'effet
restore_interruption #bloquant d'un THIS_THREAD::DISABLE_INTERRUPTION,
#jusqu'à sa destruction.
THIS_THREAD::
DISABLE_INTERRUPTION() #Constructor vide.
THIS_THREAD::
RESTORE_INTERRUPTION
(THIS_THREAD::
DISABLE_INTERRUPTION) #Constructor.
this_thread:: #Renvoie true si aucun THIS_THREAD::DISABLE_INTERRUPTION
interruption_enabled() #ne bloque actuellement les interrupt()
thread::id #Classe désignant l'identifiant unique d'un THREAD.
#Tous les THREAD associés à aucun thread ont le même
#THREAD::ID.
THREAD::ID() #Construit un THREAD::ID identique à celui associé aux
#THREAD n'étant associés à aucun thread.
THREAD::ID == THRED::ID2
THREAD::ID != THRED::ID2
THREAD::ID < THRED::ID2
THREAD::ID > THRED::ID2
THREAD::ID <= THRED::ID2
THREAD::ID >= THRED::ID2#Tests d'égalités.
OSTREAM << THREAD::ID #Ecrit l'identifiant de THREAD::ID sur OSTREAM
thread_group #Classe désignant un ensemble de THREAD liés les uns
#aux autres. Ne peut pas être copié (ni Assignable,
#ni CopyConstructible)
THREAD_GROUP() #Construit un THREAD_GROUP ne contenant aucun THREAD.
~THREAD_GROUP() #A sa destruction, tous les THREAD qu'il contient sont
#détruits.
THREAD_GROUP. #Rajoute THREAD dans le THREAD_GROUP. La mémoire de
add_thread(THREAD_ADR) #THREAD_ADR doit être allouée.
THREAD_GROUP. #Supprime THREAD du THREAD_GROUP (ne supprime pas
remove_thread(THRED_ADR)#THREAD lui-même). La mémoire de THREAD_ADR doit être
#allouée.
THREAD_GROUP. #Rajoute thread(FUNCTOR) dans le THREAD_GROUP. Pour
create_thread(FUNCTOR) #donner des arguments à FUNCTOR, utiliser par exemple
#std::bind() ou boost::bind()
#Renvoie le THREAD créé sous forme de THREAD_ADR.
THREAD_GROUP.join_all() #Ne fait rien si aucun THREAD n'est pas associé à un
#thread. Sinon, attend que les threads de tous les
#THREAD s'achèvent.
THREAD_GROUP.
interrupt_all() #Envoie interrupt() à chaque THREAD.
THREAD_GROUP.size() #Renvoie le nombre de THREAD du THREAD_GROUP.
MUTEXS ==> #Les mutexs sont utilisés pour verrouiller une
#ressource utilisée (écriture) par un thread pouvant
#être utilisée (écriture ou lecture) par un autre
#thread en même temps.
#Ils ne sont pas copiables, même par référence.
#Les mutexs doivent être implémentés de préférence dans
#la même classe que la ressource (permet d'éviter de
#les mettre globaux).
#Pour remplir un de ces concepts, il faut définir
#l'ensemble des fonctions de la classe indiquée (dont
#exceptions lancées).
#Pour les arguments de timed_lock : TIME_DURATION est
#en fait un template T const&, et PTIME un ptime const&
Lockable #Concept d'un mutex et recursive_mutex.
TimedLockable #Concept d'un timed_mutex et recursive_timed_mutex
#(refine le concept Lockable)
SharedLockable #Concept d'un shared_mutex (refine le concept
#TimedLockable), hors upgrade.
UpgradeLockable #Concept d'un shared_mutex (refine le concept
#SharedLockable), avec upgrade.
LOCKABLE #Nom que je donne à tous ces mutexs.
mutex #
timed_mutex #
recursive_mutex #
recursive_timed_mutex #
shared_mutex #Différentes classes de mutexs : voir ci-dessous
OWNERSHIPS ==> #Le schéma de la bibliothèque est que : verrouiller une
#ressource avec un certain mutex donne conceptuellement
#une ownership sur cette ressource. On indique pas
#précisément la ressource, il s'agit de celle utilisée
#entre le verrouillage et le déverrouillage du mutex.
#Les cas de figure sont :
# - ou une seul exclusive owner (écriture/lecture)
# - ou plusieurs shared, avec éventuellement un (et
# un seul) upgradable (lecture)
#Ainsi, cela ne pose pas de problème si plusieurs
#threads lisent en même temps, mais oui si l'un d'eux
#écrit alors.
#Les classes et fonctions sont :
------------\ etc. etc.
| x |
| [timed_][try_]| /-------------\ |unlock()
| lock()+-----| EXCLUSIVE |<---+
recursive_ | +---->| LEVEL 2 |----+
[timed_] | [timed_][try_]| \-------------/ |
mutex | lock()| |unlock()
--------+---+ | |
[timed_]| | [timed_][try_] | /-------------\ |
mutex | | lock() #EUS# +-----| EXCLUSIVE |<---+ unlock()
| | +----------------------->| LEVEL 1 |------------------------+
--------/ | | +---->\-------------/----+ |
| | unlock_uprade| | unlock_and_ |
| | _and_lock() | |lock_upgrade() |
| | #EUS# | /-------------\ | |
| | +-----| UPGRADABLE |<---+ |
| | +----------->| |------------+ |
| | | \-------------/ | |
| | | |unlock_upgrade_ | |
shared_ | | | | and_lock_ | |
mutex | | lock_ | v shared() | |
| | upgrade()| /-------------\ | unlock_ |
| | #EU# | | SHARED | |upgrade() |
| | | \-------------/ | |
| | | [timed_][try_]x | | |
| | | lock_shared()| |unlock_shared() | |
| | | #E# | v | |
| | | /-------------\ | |
| | +------------| NONE |<-----------+ |
------------/ +------------------------\-------------/<-----------------------+
SCHEMA ==> #Les classes à gauche sont au même niveau que les
#CLASSFK qu'elles peuvent invoquer.
# #E# indique que cette fonction est bloquante et ne se
#résout que lorsque (ou si) aucun thread ne possède une
#Exclusive ownership sur l'objet. #U# indique la même
#chose pour Upgradable own., #S# pour Shared own.
#Les fonctions commençant par try_ ne sont pas
#bloquantes : si un autre thread possède une ownership
#problématique, elles échouent directement et renvoient
#false.
#Les fonctions commençant par timed_ sont bloquantes,
#mais échouent après un certain temps, et renvoient
#alors false. timed_lock() n'est pas disponible pour
#mutex et recursive_mutex (contrairement à timed_lock et
#recursive_timed_mutex)
#Les fonctions de lock (et non d'unlock) lancent une
#exception thread_resource_error en cas de problème.
#Toutes les fonctions sont de type VOID, sauf celles
#commençant par timed_ et try_, qui sont de type BOOL
#(à mettre dans un "if"). Aucune fonction ne prend
#d'argument, sauf celles commençant par timed_, qui
#prennent un argument de temps relatif POSIX_TIME::
#TIME_DURATION ou absolu POSIX_TIME::PTIME (ce dernier
#seulement pour timed_lock())
lock(LOCKABLE...) #Permet de faire que chaque LOCKABLE invoque
try_lock(LOCKABLE...) #[try_]lock(), mais en plus court, et dans un ordre tel
#que l'on évite au maximum les deadlocks.
#Pour try_lock : si un try_lock échoue, tous les
#LOCKABLE acquis jusqu'ici sont libérés, les autres ne
#sont pas effectués, et l'index du LOCKABLE
#problématique est renvoyé (commençant à 0). Sinon, -1
#est renvoyé.
#5 LOCKABLE maximum.
lock(FW_ITVR1, FW_ITVR2)
try_lock(FW_ITVR1, #Pareil mais prend les LOCKABLE dans un container de
FW_ITVR2) #LOCKABLE.
VERROU RAII #Lorsqu'un LOCKABLE est locked, si une exception est
#lancée et interrompt le thread, le LOCKABLE reste
#locked, provoquant un deadlock. Pour éviter cela, on
#utilise des classes RAII qui, lors de leur
#instantiation, lock un LOCKABLE et, lors de leur
#destruction, unlock un LOCKABLE. Ainsi, en cas
#d'exception, le verrou RAII est détruit.
#Le LOCKABLE est donc unlocked dès que la lifetime du
#verrou RAII s'achève, c'est pourquoi il peut être
#utile de mettre un bloc { } autout d'une section
#critique :
# - {
# VERROU(LOCKABLE);
# //utilisation de la ressource
# } // destruction de VERROU, LOCKABLE unlocked
#C'est inutile s'il y a déjà un bloc { } autour, et
#que VERROU a été déclaré dans celui-ci, réduisant donc
#la lifetime de VERROU (d'une fonction, d'une structure
#ou d'une boucle)
lock_guard <WVAR> #Ensemble de verrous RAII que j'appelerai VERROU.
unique_lock <WVAR> #Ils sont en général instantiés sous la forme
shared_lock <WVAR> #VERROU(LOCKABLE), invoquant alors une forme de "lock()"
upgrade_lock <WVAR> #en fonction du verrou RAII, et invoquant l'"unlock()"
upgrade_to_unique_lock #correspondant lors du destructor.
<WVAR> #WVAR doit être le type de LOCKABLE.
#Un VERROU donné ne peut être utilisé qu'avec un
#LOCKABLE dont le type est >=. Soit les LOCKABLE selon
#l'ordre :
# - [recursive]mutex < [recursive]timed_mutex
# < shared_mutex
#Cf le tableau.
try_lock_wrapper<WVAR> #Comme unique/shared_lock, mais rajoute des try_* sur
#un WVAR (LOCKABLE), qui doit être shared_mutex ou
#unique_mutex.
lockable:: #Typedef vers try_lock_wrapper<lockable> (lockable étant
scoped_try_lock #shared_mutex ou unique_mutex)
lockable::scoped_lock #Typedef vers unique_lock<lockable> (lockable étant
#tout Lockable sauf shared_mutex)
lockable:: #Typedef vers unique_lock<lockable> (lockable étant
scoped_timed_lock #timed_mutex ou recursive_timed_mutex)
VERROU(LOCKABLE) #Appelle LOCKABLE."lock()". cf le tableau pour la
#fonction "lock()" utilisée (dépend de VERROU)
VERROU(LOCKABLE[, ARG]) #Appelle un autre LOCKABLE."lock()" : cf tableau.
VERROU() #N'associe VERROU à aucun LOCKABLE.
VERROU #Move un VERROU2.
(boost::move(VERROU2)) #VERROU2 doit être le même type. Exceptions :
#unique_lock, shared_lock et upgrade_lock en VERROU2
#peuvent être pris par des VERROU unique_lock ou
#upgrade_lock
VERROU(LOCKABLE, #Associe VERROU à un LOCKABLE, mais ne le lock pas.
boost::defer_lock) #Il faut donc appeler VERROU.mutex()->lock() ou
#VERROU.lock() plus tard pour le faire.
#defer_lock est un tag.
VERROU(LOCKABLE, #Associe un VERROU déjà locked à LOCKABLE, et ne tente
boost::adopt_lock) #donc pas de le locker. La destruction de VERROU
#appelera tout de même unlock().
#Utile pour partager un LOCKABLE entre deux verrous, ou
#pour locker LOCKABLE sans VERROU, puis l'associer à un
#VERROU.
UPGRADE_TO_UNIQUE_LOCK #UPGRADE_TO_UNIQUE_LOCK est spécial : il s'instantie à
(UPGRADE_LOCK) #partir d'un autre verrou UPGRADE_LOCK.
~VERROU() #Appelle LOCKABLE."unlock()". cf le tableau pour la
#fonction "unlock()" utilisée (dépend de VERROU)
UPGRADE_LOCK.lock() #
UPGRADE_LOCK.try_lock() #
UPGRADE_LOCK.timed_lock
(ARG) #Appelle un autre LOCKABLE."lock()" : cf tableau.
UPGRADE_LOCK.unlock() #Appelle un autre LOCKABLE."unlock()" : cf tableau.
+----------+-----------+-----------+-----------+------------+-----------+
|lock_guard|unique_lock|shared_lock| try_lock_ |upgrade_lock|upgrade_to_|
| | | | wrapper<T>| |unique_lock|
+------------------+----------+-----------+-----------+-----------+------------+-----------+
| template / | mutex | mutex | shared_ | [shared_]| shared_ | shared_ |
| argument minimal | | | mutex | mutex | mutex | mutex |
+------------------+----------+-----------+-----------+-----------+------------+-----------+
| VERROU(LOCKABLE) | lock() | lock() | lock_ | try_lock | lock_ | |
| | | | shared() | [_shared]| upgrade() | |
| VERROU | | | | | | unlock_ |
| (UPGRADE_LOCK) | | | | | | upgrade_ |
| | | | | | | and_lock()|
| ~VERROU() | unlock() | unlock() | unlock_ | unlock | unlock_ | unlock_and|
| | | | shared() | shared() | upgrade() | _lock_ |
| | | | | | | upgrade() |
+------------------+----------+-----------+-----------+-----------+------------+-----------+
| VERROU() | | oui | oui | oui | oui | |
| VERROU(LOCKABLE, | oui | oui | oui | oui | oui | |
|boost::adopt_lock)# | | | | | |
| VERROU(LOCKABLE, | | oui | oui | oui | oui | |
|boost::defer_lock)# | | | | | |
| VERROU(LOCKABLE, | | try_lock()| try_lock_ | try_lock | | |
|boost::try_to_lock)# | | shared() | [_shared]| | |
| VERROU(LOCKABLE, | | timed_ |timed_lock_| | | |
| ARG) | | lock(ARG) |shared(ARG)| | | |
| | | (slt si | | | | |
| | |timed_mutex| | | | |
| | | minimum) | | | | |
| VERROU.lock() | | lock() | lock() | lock() | lock_ | |
| | | | | | upgrade() | |
| VERROU.try_lock()| | try_lock()| try_lock()| try_lock()| | |
| VERROU.timed_ | | timed_ | timed_ | | | |
| lock(ARG) | | lock(ARG) | lock(ARG) | | | |
| VERROU.unlock() | | unlock() | unlock() | unlock() | unlock_ | |
| | | | | | upgrade() | |
+------------------+----------+-----------+-----------+-----------+------------+-----------+
| VERROU.swap | | oui | oui | oui | oui | oui |
| (VERROU2) | | | | | | |
| ( VERROU ) | | oui | oui | oui | oui | oui |
|VERROU.owns_lock()| | oui | oui | oui | oui | oui |
| ! VERROU | | oui | oui | oui | oui | oui |
| VERROU.mutex() | | oui | oui | oui | | |
| VERROU.release() | | oui | oui | oui | | |
+------------------+----------+-----------+-----------+-----------+------------+-----------+
VERROU.swap(VERROU2) #Swappe VERROU et VERROU2 (doit être le même type de
#VERROU).
( VERROU ) #Renvoie true si un LOCKABLE est actuellement associé et
VERROU.owns_lock() #locked.
! VERROU #Contraire.
VERROU.mutex() #Renvoie le LOCKABLE associé sous forme de LOCKABLE_ADR,
#ou NULL si aucun LOCKABLE n'est associé.
VERROU.release() #LOCKABLE n'est plus associé à VERROU (mais n'est pas
#unlocked s'il a été locked)
condition_variable_any #Condition variable.
#Penser à faire notify_all() avant destruction de condition_variable_any
#Attention : si l'on fait notify_* alors que thread n'a pas encore fait wait(), notify_* est perdu,
#et wait() peut bloquer entrainant un deadlock. Ne pas assumer donc qu'il y a un wait(), mais
#considérer plutôt "si jamais y a un wait".
CONDITION_VARIABLE_ANY()#Lance thread_resource_error si erreur.
....wait( VERROU #Fait que le thread courant sleep jusqu'à un weak up via ....notify_* ou, si PTIME, jusqu'à PTIME.
[, POSIX_TIME::PTIME] #Si PREDIC, il est effectué avant le premier wait() : si true, pas de wait() ; et après chaque wake up,
[, PREDIC]) #si false, nouveau wait(). Lance thread_resource_error si erreur.
....timed_wait( VERROU,
POSIX_TIME::
TIME_DURATION) #Pareil, mais utilise une TIME_DURATION.
....notify_one() #wake up un des thread dormant.
....notify_all() #wake up tous les threads dormants.
condition_variable #comme condition_variable_any, mais plus efficient, mais ne peut être utilisé qu'avec des
#unique_lock<mutex>
barrier #Classe représentant le concept de rendezvous.
BARRIER(UINT_VAL) #Instantie une barrière, lié au nombre UINT_VAL
#Une fois qu'UINT_VAL threads auront exécuter
#BARRIER.wait(), tous les threads cesseront d'attendre.
#A mettre près d'une ressource, comme les mutexs.
#Lance thread_resource_error si erreur.
#Non copiable, non movable.
BARRIER.wait() #Décrémente de 1 le nombre associé à BARRIER. Si ce
#nombre n'est pas 0, attend qu'il le soit.
#Une fois débloqué :
# - Renvoie true pour un seul des threads ayant fait
# wait() (par exemple le premier)
# - n'est pas détruit mais réinitialisé à UINT_VAL.
#Lance thread_resource_error si erreur.
once_flag #Type de flag, à initialiser avec BOOST_ONCE_INIT :
# - once_flag VAR = BOOST_ONCE_INIT;
call_once(ONCE_FLAG_VAR,#Invoque FUNCTOR, à moins que call_once ait déjà été
FUNCTOR) #invoqué avec le même FUNCTOR et le même ONCE_FLAG_VAR.
#Permet donc d'invoquer une seule fois un functor donné,
#pendant la lifetime d'ONCE_FLAG_VAR.
#FUNCTOR est CopyConstructible, pas de side effectes, et
#invoquer une copie doit être pareil qu'invoquer la
#référence.
#Lance thread_resource_error si erreur.
/=+===============================+=\
/ : : \
)==: A FAIRE :==(
\ :_______________________________: /
\=+===============================+=/
- futures, thread local storage (TLS)