> For the complete documentation index, see [llms.txt](https://concorrencia101.leandronsp.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://concorrencia101.leandronsp.com/parte-ii-concorrencia-em-diferentes-linguagens/concorrencia-em-c/race-condition-e-sincronizacao-de-threads-com-mutex.md).

# Race condition e sincronização de threads com mutex

Para entendermos o problema que a *sincronização com mutex* resolve, vamos primeiro trazer o problema.&#x20;

A ideia é escrever um programa que cria 5 threads, onde cada thread faz um **incremento de 100 mil vezes** em uma variável (counter) compartilhada entre todas as threads.&#x20;

Ao fim do programa, queremos que o *counter* tenha um valor total de 500.000, ou seja, 5 threads x 100.000. Certo? Vamos então à implementação do programa:

```c
#include <stdio.h>
#include <pthread.h>

#define NUM_THREADS 5
#define INCREMENTS 100000

int counter = 0; // Variável compartilhada entre as threads

void* increment(void* arg) {
	for (int i = 0; i < INCREMENTS; i++) {
		counter++; // Incrementa a variável compartilhada
	}
	return NULL;
}

int main() {
	pthread_t threads[NUM_THREADS];

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

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

	printf("Valor final do counter compartilhado: %d (esperado: %d)\n", counter, NUM_THREADS * INCREMENTS);
	return 0;
}
```

Tudo ok até aqui, pois os comentários no código são auto-explicativos. Vamos executar o programa e:

```
Valor final do counter compartilhado: 282989 (esperado: 500000)
```

*Eita!* Note que o valor final do counter ficou bem abaixo do esperado. Experimente rodar outras vezes e repare que a cada execução, o valor final será diferente.&#x20;

Isto, *senhoras e senhores*, é a maravilha da concorrência. Não temos controle algum sobre a ordem e execução das tarefas!

> Sim, vou repetir isso inúmeras vezes neste guia kk

## Race condition

O que temos aqui é examente um cenário de **race condition**, ou *condição de corrida*, onde o valor final de um recurso compartlihado depende da ordem de execução das threads. Em outras palavras, este recurso precisa ser **sincronizado** entre as threads.&#x20;

E para isto, recorremos ao uso de travas - **locks** - que, para nossa sorte, a biblioteca padrão implementa uma abstração chamada **mutex** (exclusão mútua), através do uso da função `pthread_mutex_lock` .

## Mutex

O uso de mutex em C é muito simples. Tudo o que precisamos é de criar uma variável *compartilhada* que irá representar o mutex:

```c
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
```

E em volta da mutação do recurso, fazemos o bloqueio e desbloqueio do mutex:

```c
pthread_mutex_lock(&mutex);    // Bloqueia o mutex
counter++;                     // Incrementa a variável compartilhada
pthread_mutex_unlock(&mutex);  // Desbloqueia o mutex
```

O que vai acontecer, na prática, é que quando uma thread estiver com o mutex, e caso outra tente acessar o mesmo mutex, o sistema irá colocar esta outra thread em "wait" até que o mutex seja liberado (unlock).

<figure><img src="/files/gC6zp3hIfpHFRsk0Jb1p" alt="" width="563"><figcaption></figcaption></figure>

Agora vamos à implementação completa do código, sincronizado com mutex:

{% code title="race-condition-mutex.c" lineNumbers="true" %}

```c
#include <stdio.h>
#include <pthread.h>

#define NUM_THREADS 5
#define INCREMENTS 100000

int counter = 0; // Variável compartilhada entre as threads
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // Mutex para proteger o acesso

void* increment(void* arg) {
	for (int i = 0; i < INCREMENTS; i++) {
		pthread_mutex_lock(&mutex); // Bloqueia o mutex
		counter++; // Incrementa a variável compartilhada
		pthread_mutex_unlock(&mutex); // Desbloqueia o mutex
	}
	return NULL;
}

int main() {
	pthread_t threads[NUM_THREADS];

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

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

	printf("Valor final do counter compartilhado: %d (esperado: %d)\n", counter, NUM_THREADS * INCREMENTS);
	return 0;
}
```

{% endcode %}

```
Valor final do counter compartilhado: 500000 (esperado: 500000)
```

**Yay!** *Quantas palmas merece o mutex?*
