无法在c++中生成具有列表的Producer Consumer实例



伙计们。我正在学习生产者-消费者问题。我的教授给了我们一个使用经典int array在两个线程之间共享资源的示例代码。它按预期工作,但是,我想使用C++中的std:list类来尝试它,但它没有按预期工作。消费者似乎不尊重sem_wait(&full);,所以当共享列表中没有任何内容时,它会尝试多次消费。

带有阵列缓冲区的原始代码

#include    <pthread.h>
#include    <semaphore.h>
#include    <stdlib.h>
#include    <stdio.h>
#include    <unistd.h>
#define    N 2
#define    TRUE 1
int    buffer[N], in = 0, out = 0;
sem_t  empty, full, mutexC, mutexP;
void *producer(void *arg) {
while(TRUE) {
sleep(rand()%5);
sem_wait(&empty);
sem_wait(&mutexP);

buffer[in] = rand() % 100;
printf("Producing buffer[%d] = %dn", in, buffer[in]);
in= (in+1) % N;
sem_post(&mutexP);
sem_post(&full);

}
}
void *consumer(void *arg) {
while(TRUE) {

sleep(rand()%5);
sem_wait(&full);
sem_wait(&mutexC);

printf("Consuming buffer[%d] = %dn", out, buffer[out]);
out = (out+1) % N;

sem_post(&mutexC);
sem_post(&empty);

}
}
int main(int argc, char *argv[ ]) {
pthread_t cons, prod;
sem_init(&mutexC, 0, 1);
sem_init(&mutexP, 0, 1);
sem_init(&empty, 0, N);
sem_init(&full, 0, 0);

pthread_create(&prod, NULL, producer, NULL);
pthread_create(&cons, NULL, consumer, NULL);

pthread_exit(0);
}

我的清单实现:

#include    <pthread.h>
#include    <semaphore.h>
#include    <stdlib.h>
#include    <unistd.h>
#include    <iostream>
#include    <list>
#define    TRUE 1
#define    N 2
using namespace std;
list<int> sharedList;
sem_t  empty, full, mutexC, mutexP;
void *producer(void *arg) {
while(TRUE) {

sleep(rand()%5);
sem_wait(&empty);
sem_wait(&mutexP);
int prod = rand() % 100;
cout << "producing: " << prod << endl;
sharedList.push_back(prod);
sem_post(&mutexP);
sem_post(&full);

}
}
void *consumer(void *arg) {
while(TRUE) {

sleep(rand()%5);
sem_wait(&full);
sem_wait(&mutexC);

if (!sharedList.empty()) {
cout << "consuming: ";
cout << sharedList.front() << endl;
sharedList.pop_front();
} else {
cout << "not possible to consume" << endl;
}
sem_post(&mutexC);
sem_post(&empty);
}
}
int main(int argc, char *argv[ ]) {
pthread_t cons, prod;
sem_init(&mutexC, 0, 1);
sem_init(&mutexP, 0, 1);
sem_init(&empty, 0, N);
sem_init(&full, 0, 0);

pthread_create(&prod, NULL, producer, NULL);
pthread_create(&cons, NULL, consumer, NULL);

pthread_exit(0);
}

来自我的实现的意外日志:

producing: 73
consuming: 73
not possible to consume
producing: 44
consuming: 44
producing: 9
producing: 65
consuming: 9
producing: 87
consuming: 65
consuming: producing: 29
87
not possible to consume
consuming: 29
producing: 9
producing: 60
consuming: 9
producing: 78

有人能向我解释一下发生了什么事吗?提前感谢!

首先,请注意在两个程序中:

  • 由于只有一个生产者在争夺信号量mutexP,该信号量没有任何用处
  • 同样,只有一个消费者在争夺信号量mutexC,这也没有任何用处

现在,考虑一下在您的第一个程序中,用值2而不是值1初始化信号量empty的目的是什么:我想您会同意这样做允许生产者与消费者同时运行,领先一个位置。这是可以的,因为对不同数组元素的访问不会冲突

但是,当你的存储是std::list而不是数组时,如果其中一个线程修改了它,那么两个线程并发操作它是不合适的

  • std::list是一个单独的对象,必须对其进行同步访问,而数组只是其元素的集合,就同步要求而言,它本身不是一个不同的对象。

  • std::list具有所有操作都使用的成员(例如,保持当前列表大小),对这些成员的访问必须同步。

无论您选择查看它,都必须确保如果其中一个线程修改了std::list,则两个线程不能同时访问它。

跟进

尽管第二个代码确实有错误,但事实证明macOS确实忽略了sem_wait()。我试图用0初始化所有信号量,期望程序进入死锁,但实际上没有。因此,如果在macOS上运行,请参考这个答案

rand()%6可以生成一些有趣的序列;因此不可能消耗的伪唤醒是预期的。

除此之外,唯一令人困惑的是:

consuming: producing: 29
87
not possible to consume

这并没有那么令人困惑;io语句交错。如果他们不这样做,你会看到:

consuming: 87
producing: 29
not possible to consume

其中最后一条语句是在生产者创建29之前检查条件的结果。

相关内容

  • 没有找到相关文章

最新更新