2016-06-13 48 views
2

我开始怀疑信号量的概念;请阅读以及理解我的问题......确保这个生产者 - 消费者示例不会死锁的条件?

根据手册,sem_post将当信号量的值大于0更大解锁线程...所以,如果我有这样的代码:

void* producer(void* arg) 
{ 
    while(1) 
    { 
     sem_wait(&sem_produce); 
     sem_wait(&mutex); 
     // Insert item into buffer 
     sem_post(&mutex); 
     sem_post(&sem_consume); 
    } 
    pthread_exit(NULL); 
} 

void* consumer(void* arg) 
{ 
    while(1) 
    { 
     sem_wait(&sem_consume); 
     sem_wait(&mutex); 
     // Remove item from buffer 
     sem_post(&mutex); 
     sem_post(&sem_produce); 
    } 
    pthread_exit(NULL); 
} 

在哪里sem_consume0的值初始化,sem_produceN初始化。

如果例如N消费者在生产者之前运行并尝试消费会发生什么?那么sem_consume应该有-N的值,如果接下来有N插入,sem_consumesem_produce都应该是0,或者我错了吗?那么这意味着消费者将被卡住,因为(根据手册)sem_post将在信号量的值变得大于零时解锁线程...

因此,根据我从手册中了解并考虑上述示例,只有这种方式才能正常工作,如果sem_consume永远不会达到-N的价值。

我是对的?如果是的话,我该如何改进这个例子以免卡住?如果答案是否定的,我错了什么?

+2

“那么sem_consume应具有-N的值”。那永远不会发生。它写在整个信号手册上。 [sem_overview manual](http://man7.org/linux/man-pages/man7/sem_overview.7.html)说:“一个信号量是一个整数,它的值**永远不会低于零**”。 [sem_wait](http://man7.org/linux/man-pages/man3/sem_wait.3.html):“如果信号量当前的值为零,则调用将阻塞,直到可以执行递减(即信号量值高于零)或信号处理程序中断呼叫。“ – kaylum

+0

如果消费者在生产者之前运行,那么消费者都将等待'sem_consume',直到生产者设法执行'sem_post(&sem_consume)',对吗?只有一个消费者会为每个'sem_post(&sem_consume)'运行。在生产者被阻止等待消费者消费之前,会有'N'个项目排队。 –

+0

奇怪的是,在我的并行编程课程中,我认为我从老师那里听说,信号量的值可能是负值,并且这个负值将表示阻塞线程的数量,如果此值不能为负,那么我没有疑惑。 – OiciTrap

回答

0

所以,从我从手动理解和考虑上述 例如,仅此程序将正常工作的方法是,如果sem_consume 永远达不到-N的值。

这是正确的,信号量只是平坦不允许是一个负值的时期。正如在评论中指出了很多人,旗语手册明确说明这一点:

A semaphore is an integer whose value is never allowed to fall below zero.

而且这样的:

If the semaphore currently has the value zero, then the call blocks until either it becomes possible to perform the decrement (i.e., the semaphore value rises above zero), or a signal handler interrupts the call.

而且这样的:

Decrementing is a (possibly) blocking function. If the resulting semaphore value is negative, the calling thread or process is blocked, and cannot continue until some other thread or process increments it.

从本质上讲,信号量的整点是积极的仅是,当一个进程尝试它递减为负,这一过程被暂停,直到另一个进程增加它足够它不成为负当原始进程被允许递减时。

为了您的评论:

这是奇怪的,在我的并行编程过程中,我想我从老师那一个信号量的值可以是负值,这负值将代表阻塞的线程数听说,如果这个值不能为负,那么我毫不怀疑。

这基本上是发生了什么,但你不能查看这个值。如果你试图抓取一个当前不是正的信号量,那么试图抓住它的函数会被阻塞,直到它再次变为正值。

0

我认为sem_post和sem_wait的定义如下。

sem_wait() 将信号量的值减1,如果该值为负,则等待。

sem_post() 将信号量的值递增1,如果有一个或多个线程在等待,则唤醒一个。

因此,sem_post()并不真正检查值是否大于0。另外,如果sem_post()真的检查,那么信号量永远不能用作锁。请参阅下面的代码片段。

sem_t m; 
sem_init(&m, 0, 1) 

sem_wait(&m) 
... critical section... 
sem_post(&m) 

比方说,线程1先被调度,然后递减值为0并进入临界区。在完成之前,其他三个线程会一个接一个地调度,并且每个线程都会进一步减少信号量和块。现在,线程1再次被调度,完成关键部分并调用sem_post()。我的观点是,如果它确实检查了一个正值,那么其他线程将永远不会被安排,事实并非如此。请让我知道这是否回答你的问题。

谢谢。