2

我正在学习多线程,我想模拟生产者 - 消费者问题(如果我可以称之为信号量,则使用信号量)。

我有一个包含队列的类,生产者将整数推送到队列中,消费者检索并打印它。我模拟如下

class TestClass{
public:
    void producer( int i ){
        unique_lock<mutex> l(m);
        q.push(i);
        if( q.size() )
            cnd.notify_all();
    }

    void consumer(){
        unique_lock<mutex> l(m);
        while( q.empty() ){
            cnd.wait(l);
        }
        int tmp = q.front();
        q.pop();
        cout << "Producer got " << tmp << endl;
    }
    void ConsumerInit( int threads ){
        for( int i = 0; i < threads; i++ ){
            thrs[i] = thread(&TestClass::consumer, this );
        }
        for( auto &a : thrs )
            a.join();
    }


private:
    queue<int> q;
    vector<thread> thrs;
    mutex m;
    condition_variable cnd;
};

我使用了一个小控制台应用程序来调用数据:

int main(){
    int x;   
    TestClass t;
    int counter = 0;
    while( cin >> x ){
        if( x == 0 )
            break;
        if( x == 1)
            t.producer(counter++);
        if( x == 2 )
            t.ConsumerInit(5);
    }   
}

因此,当用户输入 1 时,会将数据推送到队列中,如果用户按下 2,则会产生线程。

以任何调用它的顺序,例如,按 1 1 然后按 2,或 2 1 1 它会引发段错误。我不确定为什么我对代码的理解如下:让我们假设 order 2 1 1

我初始化了 5 个线程,他们看到队列是空的,所以他们去睡觉了。当我将一个数字推送到队列时,它会通知所有正在休眠的线程。第一个再次唤醒锁定互斥锁并继续从队列中检索数字然后释放互斥锁,当互斥锁被释放时,另一个线程执行相同操作并解锁互斥锁,互斥锁解锁后的第三个线程仍在循环中,看到队列再次为空并再次进入睡眠状态,与所有剩余线程相同。

这个逻辑正确吗?如果是这样,为什么这会一直抛出段错误,如果不是,我感谢所有解释。

谢谢您的帮助!

//edit 通过回答建议,我将 [] 替换为 vector.push_back ,但消费者现在对数据不做任何事情,不接受或打印它。

4

4 回答 4

1

当你这样做时,你没有扩展 thrs 向量

thrs[i] = thread(&CTest::consumer, this );

你应该做

thrs.emplace_back(&CTest::consumer, this);

那就是崩溃的地方。

于 2017-03-15T21:08:44.067 回答
1

您的问题与多线程无关。您正在访问std::vector越界:

  for (int i = 0; i < threads; i++) {
        thrs[i] = thread(&CTest::consumer, this);

  //...
  vector<thread> thrs;

向量是空的thrs,您正试图访问它,就好像它有条目一样。

要显示错误,请使用:

        thrs.at(i) = thread(&CTest::consumer, this);

并且您会遇到std::out_of_range异常而不是分段错误。

于 2017-03-15T21:09:58.270 回答
1

如果输入序列不是1 1 1 1 1 ... 2. 也就是说,如果1s前面的数字2小于五。

原因如下:

如果队列大小的总元素小于 5 并且主线程调用consumerInit,则创建的五个消费者线程中的一些将阻塞等待队列接收元素。同时,主线程阻塞在join操作上。由于主线程将等待消费者线程完成,而其中一些线程正在等待数据消费,因此不会有任何进展。因此陷入僵局。

于 2017-03-15T21:34:24.203 回答
1

问题在这里:

  for( auto &a : thrs )
        a.join();

2进入等待消费者完成后,主线程在这里被阻塞。因此,在这一点之后,您认为您正在输入输入,而没有cin发生。

删除这两行,然后您可以输入1,生产者/消费者将完成他们的工作。

于 2017-03-15T21:47:04.463 回答