2017-10-13 10 views
2

나는 mutex를 사용하여 스레드간에 동기화하는이 코드가 0에서 10까지 3 번 연속으로 번호를 인쇄한다고 생각했습니다.mutex를 가진 스레드에서 이상한 인쇄가 왜 발생합니까?

#include <iostream> 
#include <mutex> 
#include <thread> 

using namespace std; 

struct A 
{ 
    void run() 
    {  
     lock_guard<mutex> l(mutex); 
     int i = 0; 
     while (i <= 10) 
      cout << "i = " << i++ << endl;    
    } 

    std::mutex mut; 
}; 

int main() 
{ 
    A a; 
    thread t1(&A::run, &a); 
    thread t2(&A::run, &a); 
    thread t3(&A::run, &a); 

    t1.join(); 
    t2.join(); 
    t3.join(); 
} 

그러나 출력의 시작은 항상 다소 손상됩니다. 나머지는 가끔은 때로는 괜찮습니다. 때로는 그렇지 않습니다. 그래서, 분명히, 그것은 동기화되지 않습니다. 그것은 하나의 스레드가 mutex에 대한 잠금을 얻었을 때 다른 스레드가 run 메소드의 본문에 들어갈 것으로 예상했기 때문에 이상합니다. 그러나 분명히 사실이 아닙니다.

i = i = 00i = 0 

i = 1 
i = 2 
i = 3 

누군가 설명 할 수 있습니까?

나는 thread 생성자에서 'a'객체를 std :: ref로 둘러 쌀 필요가 있다고 생각했지만, 그렇지 않아도 도움이되지 않습니다.

+3

어떤 사람들은 문제에 직면했을 때 "나는 쓰레드를 사용할 것입니다."라고 생각하고, 두 사람은 erpoblesms을 사용합니다. – Slava

+6

'lock_guard l (mutex); 그리고'std :: mutex mut;'? –

+0

도움이되지 않지만 잠금 장치를 사용하면 매력적이지 않습니다. 잠금 가드가있는 인쇄 메서드를 만들고 루프 내에서 print 메서드를 호출합니다. 잠금 장치는 가능한 한 최소한으로 차단되어야합니다. 인쇄를 지켜야 할 때만 모든 '실행'방법을 차단할 필요가 없습니다. – Kieveli

답변

7

이 :

lock_guard<mutex> l(mutex); 

은 아마 당신이 원하지 아닌 std::mutex 매개 변수를 받아들이는 형식 lock_guard<mutex>의 기능 l를 선언합니다. 랩 std::lock_guard 랩퍼가 제대로 사용되지 않으므로 경쟁 조건이 발생합니다.

std::lock_guard<std::mutex> l(mut); 

using namespace std;를 사용하지 않는이 혼동을 피하기 위해 : 당신은 유형 std::lock_guard의 변수를 선언하고 대신 mut 멤버 변수를 초기화 할 수 있습니다.

+2

Most Vexing Parse의 흥미로운 트위스트. – Persixty

0

오타가 다음과 같이 참조되었습니다. 'Lock_guard l (mut)이어야합니다.' 하지만 여전히 시도해보십시오.

#include <iostream> 
#include <mutex> 
#include <thread> 

using namespace std; 

struct A 
{ 
    void run() 
    {  
     int i = 0; 
     while (i <= 10) 
      printOutput(i); 
    } 

    void printOutput(int i) 
    { 
     lock_guard<mutex> l(mut); 
     cout << "i = " << i++ << endl;    
    } 

    std::mutex mut; 
}; 

int main() 
{ 
    A a; 
    thread t1(&A::run, &a); 
    thread t2(&A::run, &a); 
    thread t3(&A::run, &a); 

    t1.join(); 
    t2.join(); 
    t3.join(); 
} 

출력이 더 재미있을 것 같아요 ... 때때로. 디버그 컴파일과 함께 시도해보고 최적화하십시오 - 다르게 동작 할 수 있습니다.

1

대답은 제가 오타를 만든 것입니다. 'mut'를 쓰는 대신 'mutex'라고 입력했습니다. 이 코드는 놀랍게도 컴파일되었지만 주석에 언급 된대로이 함수는 선언했지만 뮤텍스는 잠그지 않았습니다 ('가장 짜증나는 구문 분석'). 그래서 'run'메서드의 코드가 스레드간에 동기화되지 않았습니다.

주석에서 언급했듯이 'using namespace std'를 사용하지 않으면이 오류를 방지 할 수 있습니다. 'std :: mutex'멤버 변수가 없지만 'mut '.

관련 문제