生产者消费者问题中的竞争条件

Race condition in Producer Consumer Problem

在下面的代码中,我希望 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() 函数的非原子操作(如果我错了请告诉我)。有什么办法可以避免这种情况吗?

你可以尝试用一些伪信号量替换 s, full, empty integer:

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);
}

这可以工作但是会执行繁忙的循环,而真正的信号量不会这样做,这就是为什么使用真正的信号量会更好恕我直言