条件变量的if与while



此文是linux c++的一个程序,该程序要求是给定一个缓冲区,一个生产者,一个消费者,然后要求使用条件变量,互斥量来解决读写问题,其中有个重要的知识点就是,使用信号量的时候,如何保证线程安全,如果有一个生产者,多个消费者,这种情况下,条件变量wait地方就应该使用while,而非if,如果是单生产单消费,则可以用if。具体解释见代码注释


/* ex7-4.c */
#include
#include
#define BUFFER_SIZE 4
#define OVER (-1)
struct producers
{
int buffer[BUFFER_SIZE];
pthread_mutex_t lock;
int readpos, writepos;
pthread_cond_t notempty;
pthread_cond_t notfull;
};


void init(struct producers *b)
{
pthread_mutex_init(&b->lock,NULL);
pthread_cond_init(&b->notempty,NULL);
pthread_cond_init(&b->notfull,NULL);
b->readpos=0;
b->writepos=0;
}


void put(struct producers *b, int data)
{
pthread_mutex_lock(&b->lock);
while((b->writepos+1)%BUFFER_SIZE==b->readpos)
{
pthread_cond_wait(&b->notfull,&b->lock);
}


b->buffer[b->writepos]=data;
b->writepos++;
if(b->writepos>=BUFFER_SIZE) b->writepos=0;
pthread_cond_signal(&b->notempty);
pthread_mutex_unlock(&b->lock);
}


int get(struct producers *b)
{
int data;
pthread_mutex_lock(&b->lock);
while(b->writepos==b->readpos)
{  
   //此处为何是一个while 而不是if,假设现在一个生产者写了一个单位,而且广播给两个消费者,这时候,两个消费者wait都被返回,都被唤醒,假如第一个消费者率先拿到,这时候writepos==readpos,下面该第二个消费者去拿,这时候就会越过writepos访问,导致问题,所以这里,第二个消费者在wait被唤醒后,会继续执行while判断writepos和readpos,发现这两个还是保持相等状态,则第二个消费者就要继续wait
pthread_cond_wait(&b->notempty,&b->lock);
}
data=b->buffer[b->readpos];
b->readpos++;
if(b->readpos>=BUFFER_SIZE) b->readpos=0;
pthread_cond_signal(&b->notfull);
pthread_mutex_unlock(&b->lock);
return data;
}


struct producers  buffer;
void *producer(void *data)
{
int n;
for(n=0;n<10;n++)
{
printf("Producer : %d-->\n",n);
put(&buffer,n);
}
put(&buffer,OVER);
return NULL;
}


void *consumer(void *data)
{
int d;
while(1)
{
d=get(&buffer);
if(d==OVER) break;
printf("Consumer: --> %d\n",d);
}
return NULL;
}


int main()
{
pthread_t tha,thb;
void *retval;
init(&buffer);
pthread_create(&tha,NULL,producer,0);
pthread_create(&thb,NULL,consumer,0);
pthread_join(tha,&retval);
pthread_join(thb,&retval);
return 0;


}

你可能感兴趣的:(Linux)