Para os exemplos basta usar o comando make
para compilar.
O compilador utilizado é o gcc
, basta tê-lo instalado na máquina.
Este é um exemplo de implementação de um problema clássico de sincronização chamado "Produtor-Consumidor" usando semáforos em C com POSIX (Portable Operating System Interface) threads. Neste cenário, há um buffer compartilhado entre uma thread produtora e uma thread consumidora. A thread produtora insere itens no buffer, enquanto a thread consumidora retira itens do buffer. A sincronização é realizada usando semáforos para garantir que o produtor e o consumidor não acessem o buffer ao mesmo tempo. O buffer compartilhado é tambem um exemplo de implementação de uma possivel forma de trocar mensagens entre threads. Outro exemplo de possível forma seria por meio de variaveis atomicas, mas isso não é abordado neste exemplo.
- O buffer é definido com um tamanho fixo (
BUFFER_SIZE
). - Duas threads são criadas: uma thread produtora e uma thread consumidora.
- A thread produtora gera números aleatórios (
item
) e os insere no buffer. Ela aguarda o semáforoempty
(que representa espaços vazios no buffer) antes de inserir um item. - A thread consumidora retira itens do buffer e os imprime. Ela aguarda o semáforo
full
(que representa itens no buffer) antes de retirar um item. - O programa cria as threads produtora e consumidora usando a função
pthread_create
e espera que elas terminem usando a funçãopthread_join
. - Os semáforos empty e full são inicializados com os valores apropriados (BUFFER_SIZE e 0, respectivamente) usando
sem_init
. - Após a conclusão das threads, os semáforos são destruídos usando
sem_destroy
.
Este programa cria duas threads (tid1
e tid2
) que executam a função Count
. A função Count
realiza um loop onde uma variável tmp é atualizada com o valor atual de cnt
, depois incrementa tmp e finalmente atualiza cnt
com o valor de tmp
.
Como não há sincronização adequada entre as threads para acessar e modificar a variável cnt
, uma condição de corrida ocorre. Isso significa que as threads podem interferir umas nas outras, causando resultados inconsistentes.
Se a condição de corrida não ocorrer, o valor de cnt
será igual a 2 * NITER
(o dobro do número de iterações). No entanto, devido à falta de sincronização, é provável que ocorram resultados incorretos, e verá mensagens de erro ou sucesso baseadas na verificação do valor de cnt
.
Nota: Este código é projetado para demonstrar um problema de condição de corrida
Este código é um exemplo de como o uso de mutex
pode corrigir uma condição de corrida do codigo race.c
. O problema original era que duas threads estavam acessando e modificando a variável cnt
(uma seção crítica
do código) ao mesmo tempo, causando resultados inconsistentes. O uso de mutex
corrige esse problema, garantindo que apenas uma thread tenha acesso à variável cnt
por vez.
- A variável global
cnt
é compartilhada entre as duas threadstid1
etid2
, que executam a funçãoCount
. - Antes de acessar e modificar a variável
cnt
, cada thread bloqueia o mutex usandopthread_mutex_lock(&mutex)
. - Isso garante que apenas uma thread por vez tenha acesso à variável
cnt
. - Após modificar a variável
cnt
, a thread libera o mutex usandopthread_mutex_unlock(&mutex)
. - Dessa forma, apenas uma thread pode acessar e modificar a variável
cnt
por vez, evitando condições de corrida.
Este código demonstra como usar interrupções temporais (sinais SIGALRM
) em C POSIX para agendar a execução de uma ação após um intervalo de tempo específico. Vamos dividir o código em partes para uma melhor compreensão.
- A função principal começa definindo uma estrutura
struct sigaction
chamadasa
. Nesta estrutura, o camposa_handler
é configurado para a função de tratamentoalarm_handler
, que será chamada quando o temporizador expirar. Os outros campos da estrutura são configurados para valores padrão. - A função
sigaction
é usada para configurar o tratador de sinal. Se houver um erro, a função perror exibirá uma mensagem de erro. - A função
alarm
é usada para definir um temporizador para 5 segundos. Quando esse tempo expirar, o sinalSIGALRM
será gerado, o tratadoralarm_handler
será chamado e a mensagem será impressa. - O loop
while(1)
faz com que o programa aguarde indefinidamente até que o sinalSIGALRM
seja recebido. Nesse ponto, a funçãoalarm_handler
é chamada, o que resulta na impressão da mensagem e no encerramento do programa.
Nota:
Este exemplo demonstra o uso de interrupções temporais usando sinais SIGALRM
. No entanto, perceba que o uso de while(1)
para aguardar sinais pode não ser a melhor abordagem em cenários reais, pois resultaria em alto consumo de CPU.