C ++ for 루프 인쇄 잘못된 값의 스레드


19

C ++에서 멀티 스레딩을 이해하려고 하는데이 문제가 발생했습니다 .for 루프에서 스레드를 시작하면 잘못된 값이 인쇄됩니다. 이것은 코드입니다.

#include <iostream>
#include <list>
#include <thread>

void print_id(int id){
    printf("Hello from thread %d\n", id);
}

int main() {
    int n=5;
    std::list<std::thread> threads={};
    for(int i=0; i<n; i++ ){
        threads.emplace_back(std::thread([&](){ print_id(i); }));
    }
    for(auto& t: threads){
        t.join();
    }
    return 0;
}

나는 0,1,2,3,4 값을 인쇄 할 것으로 기대했지만 종종 같은 값을 두 번 얻었습니다. 이것은 출력입니다.

Hello from thread 2
Hello from thread 3
Hello from thread 3
Hello from thread 4
Hello from thread 5

내가 뭘 놓친거야?


7
합격 i, 람다 값 [i].
rafix07

1
당신이 사용하는 emplace_back것이 이상 하다는 것을 주목할 가치가 있습니다 : emplace_back인수 목록을 가져 와서 생성자에게 넘깁니다 std::thread. 의 (rvalue) 인스턴스를 전달 std::thread했으므로 스레드를 생성 한 다음 해당 스레드를 벡터로 이동합니다. 이 작업은보다 일반적인 방법으로 더 잘 표현됩니다 push_back. 다소 관용적 인 쓰기 threads.emplace_back([i](){ print_id(i); });(제자리에서 구성) 또는 threads.push_back(std::thread([i](){ print_id(i); }));(구문 + 이동)하는 것이 더 합리적 입니다.
Milo Brandt

답변:


17

[&]구문 일으키는 i캡처 할 참조 . 따라서 i스레드가 실행될 때 예상보다 더 자주 진행됩니다. 더 심각하게 는 스레드가 실행되기 전에 범위를 벗어나 면 코드의 동작이 정의되지 않습니다i .

i가치에 의한 캡처 -즉 std::thread([i](){ print_id(i); })수정입니다.


2
덜 사용하고 자주 권장하지 않는std::thread([=](){ print_id(i); })
Wander3r

3
i기본 스레드 쓰기 및 다른 스레드 읽기와 함께 (비 원자) 데이터 레이스이기 때문에 동작이 이미 정의되어 있지 않습니다 .
호두

6

두 가지 문제 :

  1. 스레드가 실행될 때 제어 할 i수 없으므로 람다 의 변수 값 이 예상과 다를 수 있습니다.

  2. 변수 i는 루프와 루프에만 국한됩니다. 하나 이상의 스레드가 실행되기 전에 루프가 완료되면 해당 스레드는 수명이 종료 된 변수에 대한 유효하지 않은 참조를 갖습니다.

변수 를 참조 대신 i 으로 캡처하면 이러한 문제를 매우 간단하게 해결할 수 있습니다 . 그 수단은, 각 스레드는 것이다 복사본 값을 복사하고 각 스레드에 대해 고유 할 것이다.


5

또 다른 한가지 :
음주 때까지 기다릴 항상 정렬 된 순서를 가질 : 0, 1, 2, 3, ... 멀티 스레딩 실행 모드는 특이성이 있기 때문에 : 비결정론을 .

결정론은 동일한 조건에서 동일한 프로그램을 실행하면 다른 결과를 얻는다는 것을 의미합니다.

이는 OS가 CPU로드, 다른 프로세스의 우선 순위, 가능한 시스템 중단 등과 같은 여러 매개 변수에 따라 실행마다 스레드를 다르게 예약하기 때문입니다.

예제에는 5 개의 스레드 만 포함되어 있으므로 간단하고 스레드 수를 늘리고 처리 기능에서 절전 모드를 설정하면 결과가 실행마다 다를 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.