2014-12-03 4 views
7

: 나는 한 번에 하나의 스레드 액세스를 유지하기 위해 뮤텍스를 사용하더라도이 스레드가 순서대로 실행되지 않는 이유는 무엇입니까? 나는이 코드를 실행하면

Hi from thread 7 
Hi from thread 1 
Hi from thread 4 
Hi from thread 6 
Hi from thread 0 
Hi from thread 5 
Hi from thread 2 
Hi from thread 3 
Hi from thread 9 
Hi from thread 8 

:

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

std::mutex m; 

int main() 
{ 
    std::vector<std::thread> workers; 
    for (int i = 0; i < 10; ++i) 
    { 
     workers.emplace_back([i] 
     { 
      std::lock_guard<std::mutex> lock(m); 
      std::cout << "Hi from thread " << i << std::endl; 
     }); 
    } 

    std::for_each(workers.begin(), workers.end(), [] (std::thread& t) 
    { t.join(); }); 
} 

을 나는 output 얻가. 출력이 순서대로 나오지 않는 이유는 무엇입니까?

+0

하나의 스레드 액세스를 위해 –

+2

뮤텍스를 시작하는 아무 동시에 코드의 조각을 실행 중이 방지가없는 멀티 스레드 프로그래밍 어려운 :-)한다. 그런데 왜 특정 주문을 기대합니까? –

+1

"한 번에 하나의 스레드 만 액세스"는 사용자가 정확히 달성 한 것입니다. 그런데 왜 그것이 어떤 특정한 순서로 일어날 것을 기대 했습니까? – AnT

답변

19

뮤텍스가 달성하는 것은 두 스레드가 동시에 인쇄 할 수 없다는 것입니다. 그러나, 그들은 스레드가 뮤텍스를 먼저 얻는 레이싱을 계속하고 있습니다.

직렬 실행을 원하면 스레드를 전혀 피할 수 있습니다.

6

주문 스레드가 예약되는 운영 체제에 달려 있습니다. 어떤 순서로도 의지 할 수는 없습니다. 그것은 완전히 무작위라고 가정합니다.

3

std :: thread 생성자의 매개 변수로 사용되는 emplace_back에 람다를 전달합니다. cplace.com에서 아래 emplace_back copy/pasted에 대한 세부 정보를 참조하십시오.

"컨테이너의 끝에 새 요소를 추가합니다.이 요소는 일반적으로 컨테이너에서 제공하는 위치에서 현재 위치에서 요소를 생성하기 위해 placement-new를 사용하는 std :: allocator_traits :: construct를 통해 생성됩니다. 인수의 인수는 ...

http://en.cppreference.com/w/cpp/container/vector/emplace_back

이 람다의 본문에 뮤텍스가 아니오 표준 : : 스레드까지 영향을주지 .... "표준 : 앞으로 (인수)와 같은 생성자로 전달되지 않습니다 객체가 완전히 구축되어 람다 본문에 정의 된 스레드 진입 점을 실행합니다. 일부 std :: threads는 루프 중에 실행되기 시작하거나 루프가 완료 될 때까지 스레드가 시작되지 않을 수 있습니다. 이것을 휴대용 방식으로 파악할 수는 없습니다.

for-loop가 벡터의 모든 std :: threads를 생성 한 후에 OS가 스레드의 실행 순서를 결정할 때까지, 즉 출력의 임의 순서 지정 방법을 결정해야합니다.

2

실행 순서는 중요하지 않으므로 예측할 수 없으며 주어진 실행에서 실행 순서와 실행 시간이 변경됩니다.

디자인은 어떤 식 으로든 폼의 실행 순서에 의존해서는 안됩니다.

N 개의 스레드가 동기화 개체 (예 : 뮤텍스)에서 대기 중이고 뮤텍스가 해제되면 대기중인 스레드 중 어느 스레드가 각성 될지 예측할 수 없습니다. 뮤텍스는 상대적 스케줄링 우선 순위에 관계없이 다음에 수행됩니다.

비 결정론은 한 번에

관련 문제