确保此生产者 - 消费者示例不会死锁的条件?

时间:2016-06-13 05:53:45

标签: c multithreading pthreads semaphore

我开始怀疑信号量的概念;请仔细阅读以了解我的问题...

根据手册,当信号量的值大于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_consume的值初始化0sem_produce初始化N

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

因此,根据我对手册的理解并考虑上面的示例,此程序可以正常工作的唯一方法是sem_consume永远不会达到-N的值。

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

2 个答案:

答案 0 :(得分: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.

本质上,信号量只有正数的整个点是当一个进程试图将其减少为负数时,该进程将停止,直到另一个进程充分增加它以使其在原始进程被允许时不会变为负数递减。

发表评论:

  

这很奇怪,在我的并行编程课程中,我以为我从老师那里听说信号量的值可能是负数,而这个负值代表阻塞线程的数量,如果这个值不能为负则那么我毫无疑问。

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

答案 1 :(得分: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()。我的观点是,如果它确实检查了一个正值,那么其他线程将永远不会被安排,而事实并非如此。如果这回答了你的问题,请告诉我。

谢谢。