2013-04-09 3 views
4

현재 두 개의 스레드에 생산자와 소비자가 있습니다. 생성자는 Deque 유형의 정적 컨테이너에 데이터를 삽입하고 boost::condition_variable을 통해 소비자에게 deque 객체에 객체가 삽입되었음을 알리는 정적 메서드입니다. 그런 다음 소비자는 Deque 유형에서 데이터를 읽고이를 컨테이너에서 제거합니다. 두 스레드는 다음을 사용하여 통신합니다. boost::condition_variable통신은 공통 데이터 구조를 통해 두 개의 스레드를 연결합니다. 디자인 문제

다음은 추상적 인 현상입니다. 이것은 이제 객체가 Deque 형식 개체에 삽입되는

//Static Method : This is the producer. Different classes add data to the container using this method 
    void C::Add_Data(obj a) 
    { 
     try 
     {  
      int a = MyContainer.size(); 
      UpdateTextBoxA("Current Size is " + a); 
      UpdateTextBoxB("Running"); 
      MyContainer.push_back(a); 
      condition_consumer.notify_one(); //This condition is static member 
      UpdateTextBoxB("Stopped");     
     } 
     catch (std::exception& e) 
     { 
      std::string err = e.what(); 
     } 
    }//end method 


    //Consumer Method - Runs in a separate independent thread 
    void C::Read_Data() 
    { 
     while(true) 
     { 
      boost::mutex::scoped_lock lock(mutex_c); 
      while(MyContainer.size()!=0) 
      { 
       try 
       { 
        obj a = MyContainer.front(); 
        .... 
        .... 
        .... 
        MyContainer.pop_front(); 
       } 
       catch (std::exception& e) 
       { 
        std::string err = e.what(); 
       } 
      } 
      condition_consumer.wait(lock); 
     } 

    }//end method 

가 매우 빠르다 소비자와 생산자의 코드는 약 500 second.While가 TextBoxB 내가있는 동안 "정지"항상 것을 나는 발견이 실행 객체 "Running"과 "Stoped"사이를 전환한다고 가정 해보십시오. 플러스 매우 느립니다. 내가 뭘 생각하고 잘못했을지도 모르는 것에 대한 제안? 당신은 뮤텍스에서 MyContainer.push_back(a);을해야

답변

5

1) - 그렇지 않으면 당신은 정의되지 않은 동작입니다 데이터 인종을 얻을 것입니다 (+ 당신은 그것의 유형과 C++ ISO/컴파일러 버전에 따라, 너무 뮤텍스에 의해 MyContainer.size();을 보호해야 할 수도 있습니다 너는 사용한다).

2) void C::Read_Data()는해야한다 : 당신은 소비/생산 의 논리 동시 큐의 논리를 혼합하는

void C::Read_Data() 
{ 
    scoped_lock slock(mutex_c); 
    while(true) // you may also need some exit condition/mechanism 
    { 
     condition_consumer.wait(slock,[&]{return !MyContainer.empty();}); 
     // at this line MyContainer.empty()==false and slock is locked 
     // so you may pop value from deque 
    } 
} 

3). 대신 엔티티 형을 서 동시 큐 부분을 분리 할 수 ​​있습니다 : 답장을 보내

LIVE DEMO

// C++98 
template<typename T> 
class concurrent_queue 
{ 
    queue<T> q; 
    mutable mutex m; 
    mutable condition_variable c; 
public: 
    void push(const T &t) 
    { 
     (lock_guard<mutex>(m)), 
      q.push(t), 
      c.notify_one(); 
    } 
    void pop(T &result) 
    { 
     unique_lock<mutex> u(m); 
     while(q.empty()) 
      c.wait(u); 
     result = q.front(); 
     q.pop(); 
    } 
}; 

감사합니다. 당신은 조건 대기 문 [&]{return !MyContainer.empty();}

초 있었던 파라미터로 술어를 취 condition_variable::wait의 두 번째 버전이 있습니다에서 두 번째 매개 변수를 설명 할 수 없습니다. 그것은 기본적으로 그 술어가 거짓 인 동안 기다리고, "무시"하는 것을 돕는다. spurious wake-ups.

[&]{return !MyContainer.empty();} - 이것은 lambda function입니다. C++ 11의 새로운 기능입니다 - "내부에서"함수를 정의 할 수 있습니다. 당신이 C++ (11)이없는 경우, 단지 독립형 조건을 수동으로 while 루프 wait의 1 인자 버전을 사용 : 당신이 제안 당신 3 점에

while(MyContainer.empty()) condition_consumer.wait(lock); 

한 질문 큐 전체에 대한 추가 작업은 정적이고 소비자 (큐 판독기)는 별도의 스레드에서 영원히 실행되는 동안 전체 큐를 격리해야합니다. 디자인에 결함이있는 이유는 무엇입니까?

"영원히 뛰다"또는 static으로 문제가 없습니다. 디자인에 필요한 경우 static concurrent_queue<T> member을 만들 수도 있습니다.

결함은 멀티 스레드 동기화가 다른 종류의 작업과 결합된다는 것입니다. 당신이 때 는 concurrent_queue - 모든 동기화가 그 기본 내부에서 절연 및 이/생산 코드 데이터 잠금 및 대기로 오염되지 않은 소비된다

concurrent_queue<int> c; 
thread producer([&] 
{ 
    for(int i=0;i!=100;++i) 
     c.push(i); 
}); 
thread consumer([&] 
{ 
    int x; 
    do{ 
     c.pop(x); 
     std::cout << x << std::endl; 
    }while(x!=11); 
}); 
producer.join(); 
consumer.join(); 

당신이 볼 수 있듯이, 어떤 "수동이 없다 "push/pop의 동기화 및 코드가 훨씬 더 깨끗합니다.

또한 이러한 방식으로 구성 요소를 분리하면 별도로 테스트 할 수 있습니다. 또한, 그들은 더 재사용 가능 해지고 있습니다.

+0

답장을 보내 주셔서 감사합니다. 조건부 대기 문의'[&] {return! MyContainer.empty();} – MistyD

+0

두 번째 매개 변수를 설명해 주시겠습니까? ; "나는 술어를 올바르게 이해하지 못하고있다. – MistyD

+0

당신은 'while (MyContainer.empty()) condition_consumer.wait (lock);'을 사용해야합니다 ** while 루프 ** –