2017-12-20 10 views
-1

C++ 11 개의 노트를 기반으로 작성된 매우 간단한 프로듀서/소비자를 작성했으며 unique_lock()이 범위를 벗어날 때 잠금을 해제하지 않는 이유를 파악할 수 없습니다. 출력은단순한 생산자 및 소비자의 unique_lock에 대한 어려움

thread Q(&consumer); 
    thread P(&producer); 
    P.join(); 
    Q.join(); 

: - : -로

struct Message{ 
Message(int x):data(x){cout<<"+";} 
int data; 
}; 


queue<Message*> g_queue; 
condition_variable cv; 
mutex m; 

void consumer() 
{ 
    do { 
     unique_lock<mutex> lck {m}; 
     cv.wait(lck, [&](){return !g_queue.empty();}); 
     cout<<"Notified..."; 
     auto& obj = g_queue.front(); 
     std::cout<<obj->data; 
     g_queue.pop(); 
     cout<<"."; 
     lck.unlock(); -----(1) 
    } while(1); 

} 

void producer() 
{ 
    while(true){ 
      unique_lock<mutex> lck {m}; 
      Message msg{5}; 
      cout<<"Queue size:"<<g_queue.size()<<'\n'; 
      g_queue.push(&msg); 
      cv.notify_one(); 
      lck.unlock(); -------(2) 
      cout<<"-"<<'\n'; 
      this_thread::sleep_for(std::chrono::milliseconds{2000}); 
    } 
} 

그리고 그것을 사용

+Queue size:0 
-Notified... 
5.+Queue size:0 
-Notified...5 
.+Queue size:0 
-Notified...5 

그래서 기술적으로, 그래, 프로듀서 내가 준비하는 소비자에게 필요하고 소비자에 필요 Producer가 더 많은 데이터를 전송하도록 알려줍니다. 나는 무엇을 사용해야하는지 명확하지 않다. 조건 변수가 이것을하는지, 또는 unique_lock이 이것을하는지.

정확하게, 내가 필요한 이유 (1), (2)의 범위는 다음과 잠금

== 편집 == 을 해제 할 수 있습니다 때입니다 잘 작동 편집 코드,

void consumer() 
{ 
    do { 
     unique_lock<mutex> lck {m}; 
     cv.wait(lck, [&](){return !g_queue.empty();}); 
     cout<<"Notified..."; 
     auto& obj = g_queue.front(); 
     std::cout<<obj->data; 
     g_queue.pop(); 
     cout<<"."; 
    } while(1); 

} 

Message msg{5}; 
void producer() 
{ 
    while(true){ 
      unique_lock<mutex> lck {m}; 
      cout<<"Queue size:"<<g_queue.size()<<'\n'; 
      g_queue.push(&msg); 
      cv.notify_one(); 
      cout<<"-"<<'\n'; 
    } 
} 

자, 만약 수면이 위험하다면 생산자 또는 소비자에게 내가 원한다면 어떻게 조금 스로틀을 도입 할까?

+0

(1) 필요하지 않습니다. 그렇지 않으면'생산자'가 자고있는 동안 자물쇠를 잡아서 '소비자'가 굶어 버리기 때문에 (2)가 필요합니다. 또한, 프로그램은 정의되지 않은 동작을 보여줍니다 : 로컬 변수에 대한 포인터로'g_queue'를 채 웁니다.이 포인터는 포인터가 검색되고 참조 해제 될 때 아주 잘 파괴 될 수 있습니다. –

+0

예, 이해합니다. 굶주림은 내가 (1)과 (2)를 모두 제거하면서 달릴 때 볼 수있는 행동의 원인입니다. 그래서 sleep 문을 제거하고 출력에서 ​​문맥 전환을 볼 수있었습니다. 또한 지역 변수 문제를 이해하고이를 코드에서 수정했습니다. – cpp11dev

답변

0

여전히 여기에 의문점이 있는지는 모르겠지만, 조절을위한 한 가지 해결책은 큐가 생산자에서 성장할 수있는 최대 크기를 갖는 것입니다. 대기열이이 크기에 도달하면 생산자는 다른 조건 변수를 기다립니다. 큐가 특정 크기 아래로 떨어지면 소비자는이 두 번째 조건 변수를 알립니다. (약간의 히스테리 시스를 제공하기 위해서는 아마도 후자의 크기가 최대 값보다 약간 작을 것입니다.)이 새로운 조건 변수에서 기다리는 술어는 g_queue.size() >= max_size입니다.

+0

네, 그래도 여전히 질문이었습니다. 스로틀 링을 위해 우리는 큐 버퍼 비움과 충만을 관리하기 위해 2 개의 새로운 CV가 필요합니다.이 시점에서, 최적화에 대해 생각하기 시작하지 않을 때는 스로틀 관리를 사용하기 위해 위의 코드를 다시 작성할 수 있습니다. 다시 시도하고 다시 여기로 오게하십시오. 고맙습니다. – cpp11dev