Dúvida sobre funcionamento de threads/semáforos em C

1. Dúvida sobre funcionamento de threads/semáforos em C

Sandro Ferri
sferri

(usa Ubuntu)

Enviado em 15/05/2019 - 20:09h

Olá, fiz a resolução do enunciado abaixo e está funcionando perfeitamente, porém não sei se fiz o uso correto dos semáforos (nunca usei isso antes). Gostaria de saber se é assim que se utiliza ou se o que fiz não passa de uma gambiarra das mais medonhas.

Obrigado a quem puder ajudar

Escreva um programa formado por três processos concorrentes: observador,
tratador1 e tratador2. Os processos devem executar um loop infinito, e sincronizar
suas ações com o uso de semáforos. O processo observador lê valores inteiros,
que representam a temperatura do processador durante seu uso. Se o valor lido é
menor ou igual a 40, deve ser notificado o processo tratador1. Caso o valor seja
maior que 50, deve ser notificado o processo tratador2. Cada processo tratador
deverá fazer um printf a cada 10 notificações recebidas.


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

#define NUM_THREADS 3

int cont1 = 0;
int cont2 = 0;
sem_t t1;


struct WorkUnit
{
int temp;

};



void *tratador1 (void *param) {

int valor;
sem_getvalue (&t1, &valor);

if(valor == 0){

cont1++;

if(cont1 == 10){
printf("Tratador 1 utilizado \n\n");
cont1 = 0;
}
sem_post(&t1);
}
pthread_exit(NULL);
}

void *tratador2 (void *param) {

int valor2;
sem_getvalue (&t1, &valor2);

if(valor2 == 2){

cont2++;

if(cont2 == 10){
printf("Tratador 2 utilizado \n\n");
cont2 = 0;
}

sem_wait(&t1);
}
pthread_exit(NULL);
}

void *observador (void *param) {

struct WorkUnit *wu = param;

int temp = wu->temp;



printf("Valor recebido \n\n");

if(temp <= 40) { // condicao para decrementar o semaforo
sem_wait(&t1);

}else if(temp >= 50) { // condicao para incrementar o semaforo
sem_post(&t1);

}
pthread_exit(NULL);
}

int main (){

int terror;
int n;
int t;
void *(*functions[NUM_THREADS])(void *) = {tratador2, tratador1, observador};
int valor[0];
pthread_t tids [NUM_THREADS];


sem_init (&t1, 0, 1); //iniciando o semaforo

while (1) {


printf("Digite o valor: ");
scanf("%d", valor);


for (n=0; n<NUM_THREADS; n++) {
terror = pthread_create(&tids[n],NULL, functions[n], valor);

if (terror) {
errno = terror;
perror("Falha na criação da thread");
exit(EXIT_FAILURE);
}
}


for (t = 0; t < NUM_THREADS; t++) {
terror = pthread_join(tids[t], NULL);
if (terror)
{
errno = terror;
perror("Erro no Join!");
exit(EXIT_FAILURE);
}
}
}
pthread_exit(NULL);
}



  


2. Re: Dúvida sobre funcionamento de threads/semáforos em C

Paulo
paulo1205

(usa Ubuntu)

Enviado em 16/05/2019 - 09:32h

Concordo com sua suspeita, pois o código não me parece muito alinhado com o enunciado.

A primeira diferença é que o enunciado fala em processos, e você usa threads. Não sei se isso chega a ser um erro.

Além disso, parece-me que, pelo enunciado, você deveria ter três processos ativos rodando por longo prazo, sendo um deles o leitor de informações e dois tratadores da informação lida. Seu programa cria processos com tempo de vida muito curto, e o leitor de informações não é nenhum desses processos que vão sendo criados, mas sim um quarto processo (ou primeiro, cronologicamente falando).

A forma de usar os semáforos me parece inadequada, também. Em particular, eu acho muito improvável que você tenha qualquer necessidade de usar sem_getvalue().


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)


3. Re: Dúvida sobre funcionamento de threads/semáforos em C

Sandro Ferri
sferri

(usa Ubuntu)

Enviado em 16/05/2019 - 16:08h

paulo1205 escreveu:

Concordo com sua suspeita, pois o código não me parece muito alinhado com o enunciado.

A primeira diferença é que o enunciado fala em processos, e você usa threads. Não sei se isso chega a ser um erro.

Além disso, parece-me que, pelo enunciado, você deveria ter três processos ativos rodando por longo prazo, sendo um deles o leitor de informações e dois tratadores da informação lida. Seu programa cria processos com tempo de vida muito curto, e o leitor de informações não é nenhum desses processos que vão sendo criados, mas sim um quarto processo (ou primeiro, cronologicamente falando).

A forma de usar os semáforos me parece inadequada, também. Em particular, eu acho muito improvável que você tenha qualquer necessidade de usar sem_getvalue().


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)



Então... O enunciado foi passado pela minha professora de sistemas operacionais, e ela disse que deveríamos usar as threads, por isso fiz assim.

A parte de leitura dos dados: O scan recebe o número e repassar para a thread observador, dai ela verifica o valor e dispara o semáforo para a thread certa (isso ao meu ver).

Minha dúvida era na parte do semáforo, se uso assim mesmo ou se fiz gambiarra, pq não consegui pensar em outra lógica para fazer fazer, já que nunca usei isso antes e não tenho um exemplo pra me basear. Pesquisei na internet e não achei nada que usasse 3 threads com semáforos, encontrei vários exemplos com 1-2 threads



4. Re: Dúvida sobre funcionamento de threads/semáforos em C

Paulo
paulo1205

(usa Ubuntu)

Enviado em 19/05/2019 - 00:14h

Bem, eu posso ter entendido tudo errado, mas acho sinceramente que não.

Também fico um pouco receoso de lhe mostrar o que eu entendi, porque pode ir na linha de entregar a resposta pronta (ou quase), o que não é bom nem para você nem para mim, mas não consigo imaginar um jeito de lhe mostrar o que entendi.

Então eis o que me parece.
sem_t temp1_wr, temp1_rd, temp2_wr, temp2_rd;

int temp_t1, temp_t2;

void *tratador1(void *){
static unsigned count;

// Sinaliza ao observador que ele pode gravar o dado observado.
sem_post(&temp1_wr);

// Loop infinito, como pede o enunciado.
while(1){
// Aguarda haver dado pronto para consumo.
sem_wait(&temp1_rd);
// Região crítica: Consome dado em temp_t1. Durante este tempo, não pode haver acesso simultâneo a temp1.
/* ... */
// Fim da região crítica. Sinaliza ao observador que pode gravar novo dado observado.
sem_post(&temp1_wr);

// Aqui você pode fazer o que quiser, desde que não dependa do valor compartilhado de temp1.
if(++count==10){
// Imprime mensagem.
count=0;
}
}
// Como o loop acima é infinito, nunca se vai chegar aqui...
return NULL;
}

void *tratador2(void *){
// Equivalente a tratador1(), mas trocando ‘temp1…’ por ‘temp2…’.
// (Ou talvez se possa ter um tratador só, chamado duas vezes, mas com argumentos diferentes.
// Acima eu ignorei o argumento da função, mas ele poderia ter sido usado com um ponteiro que
// incluísse os dois semáforos.)
}

void *observador(void *){
while(1){
int temp=obtem_temperatura();
if(temp<=40){
sem_wait(&temp1_wr);
temp1=temp;
sem_post(&temp1_rd);
}
else if(temp>50){
sem_wait(&temp2_wr);
temp2=temp;
sem_post(&temp2_rd);
}
}
return NULL;
}


int main(void){
sem_init(&temp1_wr, 0, 0);
sem_init(&temp1_rd, 0, 0);
sem_init(&temp2_wr, 0, 0);
sem_init(&temp2_rd, 0, 0);

// Cria as três threads apenas uma vez.
}



... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner
Linux banner
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts