Состояние гонки в задаче производителя - PullRequest
0 голосов
/ 28 октября 2018

В приведенном ниже коде я ожидал, что оператор print всегда будет печатать s=0 (поскольку это двоичный семафор, и он получил блокировку).

/// Producer Consumer problem using semaphores

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

#define BUFF_SIZ 10

int s = 1; /// binary semaphore
int full = 0;
int empt = BUFF_SIZ;

int arr[BUFF_SIZ];
int value = 100;

void wait(int *s)
{
    while(*s <= 0);
    *s = *s - 1;
}
void signal(int* s)
{
    *s = *s + 1;
}
void *producer(void* param)
{
    for(int i=0;i<BUFF_SIZ;i++)
    {
        int new_item = value;
        value++;
        wait(&empt);
        wait(&s);

        printf("s = %d\n",s);
        printf("Producer inside critical section\n");
        printf("Produced item = %d\n\n",new_item);
        arr[i] = new_item;

        signal(&s);
        signal(&full);
    }
    pthread_exit(0);
}
void *consumer(void* param)
{
    for(int i=0;i<BUFF_SIZ;i++)
    {
        wait(&full);
        wait(&s);

        printf("s = %d\n",s);
        printf("Consumer inside critical section\n");
        printf("Consumed item = %d\n\n", arr[i]);

        signal(&s);
        signal(&empt);
    }
    pthread_exit(0);
}
int main()
{
    pthread_t tid_p,tid_c;
    pthread_attr_t attr1,attr2;
    pthread_attr_init(&attr1);
    pthread_attr_init(&attr2);

    pthread_create(&tid_p,&attr1,producer,NULL);
    pthread_create(&tid_c,&attr2,consumer,NULL);

    pthread_join(tid_p,NULL);
    pthread_join(tid_c,NULL);
    return 0;
}

Однако вывод равен

s = 0
Producer inside critical section
Produced item = 100

s = 0
Producer inside critical section
Produced item = 101

s = 0
Producer inside critical section
Produced item = 102

s = -1
Consumer inside critical section
Consumed item = 100

s = 0
Producer inside critical section
Produced item = 103

s = 0
Producer inside critical section
Produced item = 104

s = -1
Consumer inside critical section
Consumed item = 101

s = 0
Consumer inside critical section
Consumed item = 102

s = 0
Consumer inside critical section
Consumed item = 103

s = 0
Consumer inside critical section
Consumed item = 104

s = -1
Producer inside critical section
Produced item = 105

s = 0
Producer inside critical section
Produced item = 106

s = 0
Producer inside critical section
Produced item = 107

s = -1
Consumer inside critical section
Consumed item = 105

s = 0
Consumer inside critical section
Consumed item = 106

s = 0
s = 0
Producer inside critical section
Produced item = 108

s = 0
Producer inside critical section
Produced item = 109

Consumer inside critical section
Consumed item = 107

s = 1
Consumer inside critical section
Consumed item = 108

s = 1
Consumer inside critical section
Consumed item = 109

Итак, по моему мнению, это вызывает состояние гонки из-за неатомарной операции функции wait() (дайте мне знать, если я ошибаюсь).Есть ли способ, которым я могу избежать этого?

1 Ответ

0 голосов
/ 28 октября 2018

вы можете попробовать заменить целое число s, полное, empt на некоторый псевдо-семафор:

struct pseudo_sem {
    int value; /// binary semaphore
    pthread_mutex_t mutex;
};
struct pseudo_sem s = { 1, PTHREAD_MUTEX_INITIALIZER };
struct pseudo_sem full = { 0, PTHREAD_MUTEX_INITIALIZER };
struct pseudo_sem empt = { BUFF_SIZ, PTHREAD_MUTEX_INITIALIZER };

void wait(struct pseudo_sem *s)
{
    pthread_mutex_lock(&s->mutex);
    while(s->value <= 0) {
        pthread_mutex_unlock(&s->mutex);
        usleep(100); // be kind, sleep a bit
        pthread_mutex_lock(&s->mutex);
    }   
    s->value--;
    pthread_mutex_unlock(&s->mutex);
}

void signal(struct pseudo_sem* s)
{
    pthread_mutex_lock(&s->mutex);
    s->value++;
    pthread_mutex_unlock(&s->mutex);
}

Это может сработать, но выполняет циклическое занятие, чего не делает настоящий семафор, поэтому использование настоящего семафорабыть намного лучше ИМХО

...