c语言 - 确保此生产者-消费者示例不会陷入僵局的条件?



我开始怀疑信号量的概念;请好好阅读以理解我的问题。。。

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

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的值,那么这个程序才能正常工作。

我是对的?如果是,我该如何改进示例,使其不会陷入困境?如果答案是否定的,我错在哪里?

因此,根据我从手册中的理解,并考虑到以上内容例如,如果sem_consume永远不要达到-N的值。

这是正确的,信号量只是平坦的,不允许是负值周期。正如许多人在评论中指出的那样,信号量手册明确指出:

信号量是一个整数,其值永远不允许低于零

这个:

如果信号量当前的值为零,则调用将阻塞,直到可以执行递减(即信号量值上升到零以上)或者信号处理程序中断呼叫。

这个:

递减是一种(可能)阻塞函数。如果得到的信号量值为负,则调用线程或进程被阻塞,并且在其他线程或进程将其递增之前无法继续

本质上,信号量为正的全部意义在于,当一个进程试图将其递减为负时,该进程将停止,直到另一个进程将其递增到足够的程度,使其在允许原始进程递减时不会变为负。

致您的评论:

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

本质上就是这样,但您无法查看此值。如果您试图获取当前不是正的信号量,那么尝试获取它的函数将被阻止,直到它再次变为正。

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

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

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

因此,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()。我的观点是,如果它真的检查了一个正值,那么其他线程将永远不会被调度,事实并非如此。如果这能回答你的问题,请告诉我。

谢谢。

最新更新