多线程程序生产者/消费者[boost]

ezz*_*rem 0 c++ multithreading boost-thread boost-mutex

我正在玩boost库和C++.我想创建一个包含生产者,conumer和堆栈的多线程程序.procuder填充堆栈,消费者从堆栈中删除items(int).一切正常(pop,push,mutex)但是当我把pop/push winthin称为线程时,我没有任何效果

我做了这个简单的代码:

#include "stdafx.h"
#include <stack>
#include <iostream>
#include <algorithm>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/date_time.hpp> 
#include <boost/signals2/mutex.hpp>
#include <ctime>

using namespace std;

/ *
* this class reprents a stack which is proteced by mutex
* Pop and push are executed by one thread each time.
*/
class ProtectedStack{
private : 
stack<int> m_Stack;
boost::signals2::mutex m;

public : 
ProtectedStack(){
}
ProtectedStack(const ProtectedStack & p){

}
void push(int x){
    m.lock();
    m_Stack.push(x);
    m.unlock();
}

void pop(){
    m.lock();
    //return m_Stack.top();
    if(!m_Stack.empty())
        m_Stack.pop();
    m.unlock(); 
}
int size(){
    return m_Stack.size();
}
bool isEmpty(){
    return m_Stack.empty();
}
int top(){
    return m_Stack.top();
}
};

/*
*The producer is the class that fills the stack. It encapsulate the thread object 
*/

class Producer{
public:
Producer(int number ){
    //create thread here but don't start here
m_Number=number;


}
void fillStack (ProtectedStack& s ) {
    int object = 3; //random value
    s.push(object);
    //cout<<"push object\n";
}

void produce (ProtectedStack & s){
    //call fill within a thread 
    m_Thread = boost::thread(&Producer::fillStack,this, s);  
}

 private :
int m_Number;
boost::thread m_Thread;

};


/* The consumer will consume the products produced by the producer */ 

class Consumer {
private : 
int m_Number;
boost::thread m_Thread;
public:
Consumer(int n){
    m_Number = n;
}

void remove(ProtectedStack &s ) {

     if(s.isEmpty()){ // if the stack is empty sleep and wait for the producer      to fill the stack
        //cout<<"stack is empty\n";
        boost::posix_time::seconds workTime(1); 
        boost::this_thread::sleep(workTime);
     }
     else{
        s.pop(); //pop it
        //cout<<"pop object\n";

     }

}

void consume (ProtectedStack & s){
    //call remove within a thread 
    m_Thread = boost::thread(&Consumer::remove, this, s);  
}

};


int main(int argc, char* argv[])  
{  



ProtectedStack s;


    Producer p(0);
    p.produce(s);

    Producer p2(1);
    p2.produce(s);

    cout<<"size after production "<<s.size()<<endl;
    Consumer c(0);
    c.consume(s);
    Consumer c2(1);
    c2.consume(s);
    cout<<"size after consumption  "<<s.size()<<endl;

getchar();
return 0;  
}  
Run Code Online (Sandbox Code Playgroud)

我在VC++ 2010/win7中运行后得到:0 0

你能帮我理解为什么当我从主要调用fillStack函数时我得到了一个效果但是当我从一个线程调用它时没有任何反应?谢谢

Sea*_*ine 5

您的示例代码遇到了其他人指出的几个同步问题:

  • 缺少对ProtectedStack的某些成员的调用的锁定.
  • 主线程可以退出而不允许工作线程加入.
  • 生产者和消费者不会像你期望的那样循环.生产者应该(当他们可以)生产时,消费者应该随着新元素被推入堆叠而继续消费.
  • 主要线程上的cout可能很好地在生产者或消费者有机会工作之前执行.

我建议在生产者和消费者之间使用条件变量进行同步.请看一下这里的生产者/消费者示例:http://en.cppreference.com/w/cpp/thread/condition_variable 这是标准库中从C++ 11开始的一个相当新的功能,从VS2012开始支持.在VS2012之前,您需要提升或使用Win32调用.

使用条件变量来解决生产者/消费者问题是很好的,因为它几乎强制使用互斥锁来锁定共享数据,并且它提供了一种信令机制,让消费者知道某些东西已经准备好被消费,所以他们没有那么旋转(这总是在消费者的响应性和轮询队列的CPU使用率之间进行权衡).它也是原子本身,它可以防止线程丢失信号的可能性,这里有一些消耗,如下所述:https://en.wikipedia.org/wiki/Sleeping_barber_problem

简要介绍一下条件变量如何解决这个问题......

  • 生产者在没有拥有互斥锁的情况下在其线程上执行所有耗时的活动.
  • 生产者锁定互斥锁,将它生成的项添加到全局数据结构(可能是某种类型的队列)中,放开互斥锁并发出信号,按顺序发送单个消费者.
  • 正在等待条件变量的消费者自动重新获取互斥锁,将该项目从队列中移除并对其进行一些处理.在此期间,生产者已经在制作新项目,但必须等到消费者完成才能将项目排队.

这会对您的代码产生以下影响:

  • 不再需要ProtectedStack,一般的堆栈/队列数据结构都可以.
  • 如果使用足够新的编译器,则无需提升 - 删除构建依赖项总是一件好事.

我觉得线程对你来说是一个新的东西,所以我只能提供建议,看看其他人如何解决同步问题,因为很难解决这个问题.对具有多个线程和共享数据的环境中发生的事情的困惑通常会导致诸如死锁之类的问题.