Variables de locking mutth pthread utilisées dans les instructions

Tout d’abord, j’ai un pressentiment qui dit que, dans une instruction if, si j’utilise la variable, cela revient à lire la variable, je dois donc la verrouiller également avec mutex (si un autre pthread pouvait le faire) . Ai-je raison de le verrouiller?

L’exemple de situation de manière simplifiée est donné ci-dessous.

dans un fil, j’utilise la déclaration ci-dessous:

if(event){ // Should I or should I not lock event here to use it // inside if statement? pthread_mutex_lock(&mutex_event); event = 0; pthread_mutex_unlock(&mutex_event); // blah blah code here // blah blah code here // blah blah code here } 

dans un autre fil que je fais

 pthread_mutex_lock(&mutex_event); event = 1; pthread_mutex_unlock(&mutex_event); 

Deuxième question, si j’ai besoin de le verrouiller, comment dois-je le faire d’une manière élégante pour les programmeurs? En d’autres termes, quelle est la convention générale. Je n’aime pas l’idée ci-dessous, car je dois attendre que toutes les lignes à l’intérieur de “if” soient exécutées pour pouvoir débloquer à nouveau le mutex.

 pthread_mutex_lock(&mutex_event); if(event){ event = 0; // blah blah code here // blah blah code here // blah blah code here } pthread_mutex_unlock(&mutex_event); 

Je suis d’accord avec cette idée, mais probablement cela pourrait paraître plus joli:

 pthread_mutex_lock(&mutex_event); if(event){ event = 0; pthread_mutex_unlock(&mutex_event); // blah blah code here // blah blah code here // blah blah code here } else { pthread_mutex_unlock(&mutex_event); } 

Je trouve que cela devient plus compliqué avec une boucle while et voici la solution primitive que j’ai:

 pthread_mutex_lock(&mutex_event); store_event = event; // store_event is local pthread_mutex_unlock(&mutex_event); while(store_event){ // blah blah code here // blah blah code here // blah blah code here } 

Chaque access à la variable partagée – write AND read – doit être protégé. Ce que vous entourez de mutex est une affaire individuelle: vous devez équilibrer les frais généraux, l’atsortingcité d’utilisation de votre variable et la clarté du code.

En outre, vous ne souhaitez pas passer trop de temps dans la zone protégée. Par conséquent, si vous synchronisez une variable deux fois dans une longue section de code, vous ne souhaitez pas verrouiller la totalité de la grande section restreinte.

Il y a évidemment un problème avec quelques lectures:

 pthread_mutex_lock(&mutex_event); if(event){ event = 0; pthread_mutex_unlock(&mutex_event); // blah blah code here // blah blah code here // blah blah code here } else pthread_mutex_unlock(&mutex_event); //awful, a hundred lines below the opening. 

Dans ce cas, il est bien préférable de laisser des «zones de synchronisation» distinctes et d’opérer sur une copie locale de la variable.

 pthread_mutex_lock(&mutex_event); event_copy = event; data_copy = data; state_copy = state; pthread_mutex_unlock(&mutex_event); if(event_copy){ // blah blah code here // blah blah code here event_copy = 0; // blah blah code here } // blah blah code here pthread_mutex_lock(&mutex_event); event = event_copy; data = data_copy; state = state_copy; pthread_mutex_unlock(&mutex_event); 

etc.

De cette façon, les utilisations fréquentes d’une variable donnée ne nécessitent pas de protection, il n’y a aucun risque d’oublier un délocking (comme l’absence de la déclaration ‘else’!) Et vous regroupez le travail en minimisant le temps passé à attendre dans les mutex ou à les verrouiller / déverrouiller.

Rappelez-vous également que pour ne pas perdre les données de synchronisation dans le cache, toutes les variables inter-thread doivent être déclarées comme étant volatile . Sinon, la propagation de votre event d’un thread à un autre peut être longue. Mais en utilisant volatile vous cassez de nombreuses optimisations du compilateur. En créant des copies locales non volatiles, vous réduisez la quantité de travail effectué autour des variables volatiles et permettez à l’optimiseur de se déchaîner sur toutes les copies sans risque de casser des éléments.

Oui, vous avez besoin de la synchronisation pour toutes les lectures.

Pour la boucle while() , vous pouvez utiliser ce modèle:

 pthread_mutex_lock(&mutex_event); while(event) { pthread_mutex_unlock(&mutex_event); // blah blah code here // blah blah code here // blah blah code here pthread_mutex_lock(&mutex_event); } pthread_mutex_unlock(&mutex_event); 

..Alors le verrou est toujours maintenu à la condition.

Oui, vous devez toujours verrouiller le mutex avant de lire ou d’écrire la variable protégée. Pour éviter le code désordonné, tout en réduisant le temps de locking, vous devez déplacer les informations d’événement vers une variable locale pouvant être utilisée après le délocking du mutex, comme ceci

 int do_blah = 0; pthread_mutex_lock(&mutex_event); if(event){ event = 0; do_blah = 1; } pthread_mutex_unlock(&mutex_event); if ( do_blah ) { // blah blah code here // blah blah code here // blah blah code here }