Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <semaphore.h>
- #include <pthread.h>
- #include <signal.h>
- int* buffer;
- int* remaining_consumers;
- int* reader_position;
- static volatile int total_writers = 0, total_readers = 0;
- static volatile int next_pos_write = 0;
- int buff_length;
- int* ID;
- pthread_t* TID;
- static volatile int next_produced_num = 0;
- sem_t *sem_critical; // regiao crítica
- sem_t *sem_r, *sem_w; // controle de leitura e escrita
- static volatile int delayed_r = 0, delayed_w = 0;
- static volatile int keep_alive = 1;
- void iniciabuffer( int numpos, int numprod, int numcons )
- {
- buff_length = numpos;
- total_writers = numprod;
- total_readers = numcons;
- // Alocação dinâmica
- buffer = (int*) malloc( buff_length * sizeof(int) );
- remaining_consumers = (int*) malloc(buff_length * sizeof(int));
- reader_position = (int*) malloc(total_readers * sizeof(int));
- ID = (int*) malloc( (total_readers + total_writers ) * sizeof(int) );
- TID = (pthread_t*) malloc( (total_readers + total_writers ) * sizeof( pthread_t) );
- if( remaining_consumers == NULL || reader_position == NULL || buffer == NULL || ID == NULL || TID == NULL )
- {
- printf("Falha na alocacao dinamica de memoria\n");
- return;
- }
- // Inicialização vetores auxiliares
- for (int i = 0; i < (total_readers + total_writers); ++i) ID[i] = i;
- for (int i = 0; i < buff_length; i++) remaining_consumers[i] = 0;
- for (int i = 0; i < total_readers; i++) reader_position[i] = 0;
- }
- void pass_baton(int current_position) {
- if (delayed_r > 0 &&
- remaining_consumers[ current_position ] > 0 &&
- (current_position != next_pos_write || remaining_consumers[ current_position ] == total_readers))
- {
- delayed_r--;
- sem_post(sem_r); // passa o bastão para delayed reader
- }
- else if (delayed_w > 0 && remaining_consumers[ next_pos_write ] == 0)
- {
- delayed_w--;
- sem_post(sem_w); // passa o bastão para delayed writer
- }
- else sem_post(sem_critical);
- }
- /*
- MODELAGEM
- < await (remaining_consumers[next_pos_write] == 0)
- buffer[next_pos_write] = item
- next_pos_write = ( next_pos_write + 1 ) % buff_length; >
- */
- void* deposita( void* id_ptr )
- {
- while( keep_alive )
- {
- sem_wait(sem_critical); // espera pra entrar na regiao critica
- int current_id = *( (int*) id_ptr );
- if (remaining_consumers[ next_pos_write ] != 0)
- {
- delayed_w++;
- sem_post(sem_critical); // sai regiao critica
- sem_wait(sem_w); // espera receber sinal para escrever
- }
- printf("Escritor de id = %d, escreveu %d na posicao do buffer = %d\n\n", current_id, next_produced_num, next_pos_write );
- buffer[next_pos_write] = next_produced_num++;
- remaining_consumers[next_pos_write] = total_readers;
- next_pos_write = ( next_pos_write + 1 ) % buff_length;
- // para fins de teste
- if( next_produced_num == 20 )
- {
- keep_alive = 0;
- }
- int current_position = reader_position[ current_id ];
- pass_baton(current_position);
- }
- return NULL;
- }
- /*
- MODELAGEM
- < await (remaining_consumers[ current_position ] > 0 &&
- (current_position != next_pos_write || remaining_consumers[ current_position ] == total_readers))
- remaining_consumers[ current_position ]--;
- reader_position[ current_id ] = nxt_position; >
- A primeira condição do await garante que existe algo para consumir
- A segunda condição garante que um consumidor não consuma um item destinado
- a outro consumidor (isso pode acontecer se o buffer estiver cheio e um consumidor
- dispara na frente dos outros, e consome o item de um consumidor atrasado).
- */
- void* consome( void* id_ptr )
- {
- while( keep_alive )
- {
- sem_wait(sem_critical); // espera pra entrar na regiao critica
- int current_id = *( (int*) id_ptr );
- int current_position = reader_position[ current_id ];
- int nxt_position = ( current_position + 1 ) % buff_length;
- // Se o buffer estiver cheio: remaining_consumers[ next_pos_write ] > 0
- // Caso contrário: remaining_consumers[ next_pos_write ] == 0
- if (remaining_consumers[ current_position ] == 0 && // não tem nada para ler
- // Se estamos testando a segunda condição, sabemos que
- // remaining_consumers[ current_position ] != 0
- // Se current_position == next_pos_write e remaining_consumers[ current_position ] != 0
- // sabemos que o buffer está cheio.
- // Se remaining_consumers[ current_position ] == total_readers, nenhum consumidor
- // consumiu o item atual. Caso contrário, o consumidor deu a volta no buffer
- // e não pode mais consumir, se não ele vai consumir o mesmo item duas vezes
- (current_position == next_pos_write &&
- remaining_consumers[ current_position ] != total_readers))
- {
- delayed_r++;
- sem_post(sem_critical); // sai regiao critica
- sem_wait(sem_r); // espera receber sinal para continuar leitura
- }
- printf("leitor %d leu o valor %d na posicao %d do buffer\n\n", current_id, buffer[current_position], current_position );
- remaining_consumers[ current_position ]--;
- reader_position[ current_id ] = nxt_position;
- current_position = nxt_position;
- pass_baton(current_position);
- }
- return NULL;
- }
- int main()
- {
- sem_w = sem_open("/sem_w", O_CREAT, 0644, 0);
- sem_r = sem_open("/sem_r", O_CREAT, 0644, 0);
- sem_critical = sem_open("/sem_critical", O_CREAT, 0644, 1);
- // vamos fazer um caso simples, com 10 posicoes de buffer, 2 escritores e 2 leitores
- iniciabuffer(10, 2, 2);
- for(int i = 0; i < total_readers; ++i)
- {
- printf("Criando o leitor de indice = %d\n\n", i );
- pthread_create( &TID[i], NULL, consome , (void *) &ID[i] );
- }
- for(int j = total_readers; j < total_readers + total_writers; ++j)
- {
- printf("Criando o escritor de indice = %d\n\n", j );
- pthread_create( &TID[j], NULL, deposita , (void *) &ID[j] );
- }
- int total = total_readers + total_writers;
- for(int i = 0; i < total; ++i)
- {
- pthread_join( TID[i], NULL );
- }
- sem_unlink("/sem_w");
- sem_unlink("/sem_r");
- sem_unlink("/sem_critical");
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement