167 | | En cours, nous avons vu le mécanisme de base, le spinlock (ou busylock) réalisant une prise de verrou par attente active et le mutex ayant aussi comme finalité de prendre un verrou, mais cette fois sans attente active, en organisant une liste d'attente des threads. Notez que nous avons présenté les spinlocks pour le noyau et les mutex pour l'utilisateur, mais il est parfaitement possible d'avoir des spinlocks en mode utilisateur (LL et SC ne sont pas des instructions privilégiées) et mutex en mode noyau. |
168 | | |
169 | | Il existe d'autres mécanismes de synchronisation, par exemple, les sémaphores, les variables de conditions, les read-write lock, ou les barrières de synchronisation. Nous allons, ici nous intéresser aux barrières. |
170 | | |
171 | | Une barrière de synchronisation est utilisée pour synchroniser les étapes de calculs réalisés par plusieurs threads. Supposons que l'on souhaite exécuter deux threads en parallèle et que l'on veuille attendre que les deux aient terminé leur travail avant de recommencer un travail. Il faut que les deux threads se donnent rendez-vous à la fin de leur calcul. |
| 167 | En cours, nous avons vu le mécanisme de base, le spinlock (ou busylock) réalisant une prise de verrou par attente active. Nous avons aussi vu le mutex ayant aussi comme finalité de prendre un verrou, mais cette fois sans attente active, en organisant une liste d'attente des threads. Notez que nous avons présenté les spinlocks pour le noyau et les mutex pour l'utilisateur, mais il est parfaitement possible d'avoir des spinlocks en mode utilisateur (LL et SC n'étant pas des instructions privilégiées) et des mutex en mode noyau. |
| 168 | |
| 169 | Il existe plein d'autres mécanismes de synchronisation, par exemple, les sémaphores, les variables de conditions, les read-write lock, ou les barrières de synchronisation. Nous allons, ici nous intéresser aux barrières. |
| 170 | |
| 171 | Les barrières de synchronisation sont utilisées pour synchroniser les étapes de calculs réalisés par plusieurs threads. Supposons que l'on souhaite exécuter deux threads en parallèle et que l'on veuille attendre que les deux aient terminé leur travail avant de recommencer un travail. Il faut que les deux threads se donnent rendez-vous à la fin de leur calcul. |
| 172 | |
| 173 | L'API des barrières est composée de trois functions (prototypes définis dans `ulib/thread.h` pour les appels systèmes coté utilisateur et dans `kernel/ksynchro.h` pour les prototypes de fonctions implémentées) c'est évidemment les mêmes prototypes (si vous ne comprenez pas pourquoi, demandez le moi). |
| 174 | |
| 175 | {{{#!c |
| 176 | //-------------------------------------------------------------------------------------------------- |
| 177 | // Barrier API |
| 178 | //-------------------------------------------------------------------------------------------------- |
| 179 | |
| 180 | /** |
| 181 | * \brief hidden barrier type, the user do not what is in the barrier structure |
| 182 | */ |
| 183 | typedef struct thread_barrier_s * thread_barrier_t; |
| 184 | |
| 185 | /** |
| 186 | * \brief creates or initialize a barrier depending the value of barrier parameter |
| 187 | * \param barrier a pointer referencing the barrier, there are two cases |
| 188 | * 1) if *barrier == NULL then allocate a new barrier, then initialize count |
| 189 | * 2) if *barrier != NULL it the barrier already exists, just initialize count |
| 190 | * \param count number of expected threads for this barrier |
| 191 | * \return SUCCESS if it all goes fine or |
| 192 | * EINVAL The value specified by count is equal to zero. |
| 193 | * ENOMEM Insufficient memory exists to initialize the barrier |
| 194 | * EBUSY The implementation has detected an attempt to reinitialize a barrier |
| 195 | * while it is in use (for example, while being used in a thread_barrier_wait() |
| 196 | * call) by another thread. |
| 197 | */ |
| 198 | extern int thread_barrier_init (thread_barrier_t * barrier, size_t count); |
| 199 | |
| 200 | /** |
| 201 | * \brief wait to the referenced barrier, it is a blocking operation for all thread but the last |
| 202 | * the last arrived thread doesn't wait and notifies the other threads which becomes READY |
| 203 | * \param barrier a pointer referencing a barrier |
| 204 | * \return SUCCESS or FEALURE |
| 205 | */ |
| 206 | extern int thread_barrier_wait (thread_barrier_t * barrier); |
| 207 | |
| 208 | /** |
| 209 | * \brief destroy the referenced barrier |
| 210 | * If a thread is waiting at the barrier, then the destruction is not done, it is an error |
| 211 | * \param barrier a pointer referencing a barrier |
| 212 | * \return SUCCESS if it all goes fine or |
| 213 | * EINVAL wrong argument |
| 214 | * EBUSY The implementation has detected an attempt to destroy a barrier |
| 215 | * while it is in use (for example, while being used in a thread_barrier_wait() |
| 216 | * call) by another thread. |
| 217 | */ |
| 218 | extern int thread_barrier_destroy (thread_barrier_t * barrier); |
| 219 | |
| 220 | }}} |