Usa Mutex Lock in C

Jinku Hu 12 ottobre 2023
Usa Mutex Lock in C

Questo articolo spiegherà diversi metodi su come utilizzare il blocco mutex in C.

Usa il tipo pthread_mutex_t e la funzione pthread_mutex_lock per proteggere la sezione critica del codice

I thread condividono gli spazi degli indirizzi, il che implica che le modifiche ai dati condivisi come le variabili globali devono essere sincronizzate; in caso contrario, ci sarà un comportamento del programma non corretto. Nota che il codice seguente crea 4 thread aggiuntivi con la chiamata pthread_create e passa func3 come punto di partenza della loro esecuzione. func3 modifica la variabile globale shared con una alla volta in un bucle di 10000 iterazioni for. Quindi, se i quattro thread incrementano il valore di shared di 10000 ciascuno, il programma dovrebbe produrre 40000.

Se esegui il codice seguente, il risultato sarà un numero intero casuale, ma non 40000. Questo comportamento è generalmente classificato come una condizione di competizione, il che implica che determinati thread accedono alla variabile condivisa senza consultarsi a vicenda, ad esempio la sincronizzazione. Vale a dire, spesso quando la loro esecuzione del bucle si interlaccia, si raggiunge l’inconsistenza negli accessi e negli archivi della variabile condivisa e, infine, si ottiene una somma errata.

La sezione di codice in cui più thread modificano lo stesso oggetto nella memoria è chiamata sezione critica. In genere, la sezione critica dovrebbe essere protetta con un qualche tipo di blocco che costringerebbe altri thread ad attendere fino a quando il thread corrente termina l’esecuzione e garantisce che tutti ottengano il valore incrementato corretto. Mutex è uno dei tipi di blocco che può essere utilizzato per proteggere la sezione critica come questo cicli for in func3.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

int shared = 0;

void* func3(void* param) {
  printf("Incrementing the shared variable...\n");
  for (int i = 0; i < 10000; ++i) {
    shared += 1;
  }
  return 0;
}

int main() {
  pthread_t threads[NUM_THREADS];

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_create(&threads[i], NULL, func3, NULL);
  }

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_join(threads[i], NULL);
  }

  printf("%d\n", shared);
  exit(EXIT_SUCCESS);
}

Produzione:

Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
30384

In questo caso, utilizzeremo la libreria dei thread POSIX e il suo tipo pthread_mutex_t incorporato. La variabile di tipo pthread_mutex_t viene solitamente dichiarata come durata di archiviazione static. Mutex dovrebbe essere inizializzato solo una volta prima di essere utilizzato. Quando il mutex è dichiarato come static, si dovrebbe usare la macro PTHREAD_MUTEX_INITIALIZER per inizializzarlo. Una volta inizializzato il mutex, i thread possono usare le funzioni pthread_mutex_lock e pthread_mutex_unlock corrispondentemente. pthread_mutex_lock blocca l’oggetto mutex passato come unico argomento. Se il mutex era già bloccato, il thread chiamante viene bloccato finché il mutex non diventa disponibile. pthread_mutex_unlock dovrebbe essere chiamato per sbloccare il mutex. Se ci sono thread in attesa sullo stesso mutex, il criterio di pianificazione determina quale ottiene il blocco dell’oggetto. Infine, chiamiamo pthread_join su ciascuno dei quattro thread e stampiamo l’intero - shared, che in questo caso dovrebbe avere il valore corretto memorizzato.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

int shared = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* func3(void* param) {
  pthread_mutex_lock(&mutex);
  printf("Incrementing the shared variable...\n");
  for (int i = 0; i < 10000; ++i) {
    shared += 1;
  }
  pthread_mutex_unlock(&mutex);
  return 0;
}

int main() {
  pthread_t threads[NUM_THREADS];

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_create(&threads[i], NULL, func3, NULL);
  }

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_join(threads[i], NULL);
  }

  printf("%d\n", shared);
  exit(EXIT_SUCCESS);
}

Produzione:

Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
40000
Autore: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook