HOWTO · C
Use Mutex Lock em C
Este artigo demonstra como usar o bloqueio mutex em C
Este artigo irá explicar vários métodos de como usar o bloqueio mutex em C.
Use o tipo pthread_mutex_t e a função pthread_mutex_lock para proteger a seção crítica do código
Threads compartilham espaços de endereço, o que implica que as modificações nos dados compartilhados, como variáveis globais, devem ser sincronizadas; caso contrário, haverá um comportamento incorreto do programa. Observe que o código a seguir cria 4 threads adicionais com a chamada pthread_create e passa func3 como ponto de partida de sua execução. func3 modifica a variável global compartilhada com uma por uma em um loop for de 10000 iterações. Portanto, se os quatro threads incrementarem o valor de compartilhado em 10000 cada, o programa deve gerar 40000.
Se você executar o código a seguir, o resultado será algum número inteiro aleatório, mas não 40000. Esse comportamento é geralmente classificado como uma condição de corrida, o que implica que determinados threads acessam a variável compartilhada sem consultar uns aos outros, ou seja, sincronização. Ou seja, frequentemente quando sua execução do loop intercala, a inconsistência é alcançada nos acessos e armazenamentos da variável compartilhada e, finalmente, uma soma incorreta é produzida.
A seção de código onde vários threads modificam o mesmo objeto na memória é chamada de seção crítica. Geralmente, a seção crítica deve ser protegida com algum tipo de bloqueio que forçaria outros encadeamentos a esperar até que o encadeamento atual termine a execução e garanta que todos obtenham o valor incrementado correto. Mutex é um dos tipos de bloqueio que podem ser utilizados para proteger a seção crítica como este loop for em 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);
}
Resultado:
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
30384
Neste caso, utilizaremos a biblioteca de threads POSIX e seu tipo integrado pthread_mutex_t. A variável do tipo pthread_mutex_t é geralmente declarada como duração de armazenamento static. Mutex deve ser inicializado apenas uma vez antes de ser usado. Quando o mutex é declarado como static, deve-se usar a macro PTHREAD_MUTEX_INITIALIZER para inicializá-lo. Uma vez que o mutex é inicializado, os threads podem usar as funções pthread_mutex_lock e pthread_mutex_unlock correspondentemente. pthread_mutex_lock bloqueia o objeto mutex passado como o único argumento. Se o mutex já estiver bloqueado, o thread de chamada será bloqueado até que o mutex se torne disponível. pthread_mutex_unlock deve ser chamado para desbloquear o mutex. Se houver threads esperando no mesmo mutex, a política de agendamento determina qual delas obtém o bloqueio do objeto. Finalmente, chamamos pthread_join em cada uma das quatro threads e imprimimos o inteiro - shared, que neste caso deve ter o valor correto armazenado.
#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);
}
Resultado:
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
40000