Use Mutex Lock 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
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