2017-02-11 9 views
1

일부 작업을 수행하는 여러 스레드를 시작하는 코드가 있습니다. 실패한 경우 공유 변수를 false으로 설정합니다.thread :: join에서 synchronized-with relationship이있는 암시 적 메모리 장벽이 있습니까?

그러면 주 스레드가 모든 작업 스레드를 조인합니다.

#include <thread> 
#include <atomic> 
#include <vector> 
#include <iostream> 
#include <cassert> 

using namespace std; 

//atomic_bool success = true; 
bool success = true; 

int main() 
{ 
    vector<thread> v; 
    for (int i = 0; i < 10; ++i) 
    { 
     v.emplace_back([=] 
     { 
      if (i == 5 || i == 6) 
      { 
       //success.store(false, memory_order_release); 
       success = false; 
      } 
     }); 
    } 
    for (auto& t : v) 
     t.join(); 

    //assert(success.load(memory_order_acquire) == false); 
    assert(success == false); 

    cout << "Finished" << endl; 
    cin.get(); 
    return 0; 
} 

메인 스레드가 비록 사실로 성공 변수를 읽을 가능성이 있습니다 :이 시뮬레이션은 대략 이렇게 (내가 필요할 경우 나도 몰라하는 가능한 수정에서 주석) 보이는 근로자 중 한 명이 거짓으로 설정했습니다?

나는 스레드가 :: 가입() 전체 메모리 장벽 ( source)하지만 그, 동기화-와 관계 성공 메인 스레드에서 변수를 읽을 다음과 의미 않는 것을 발견 그래서 우리 최신 가치를 보장 받습니까?

이 경우에는 (주석이 달린 코드에 게시 된) 수정본이 필요합니까 (아니면이 수정본이 잘못되었을 때 다른 수정이 필요합니까?)?

(이 휘발성하지 이후) 변수가 멀리 최적화 될 것이며 우리가 스레드 :: 가입에 암시 적 메모리 장벽을 존재하는 suppossed에 관계없이 의 이전 값을 얻을 것이다 성공 읽을 가능성이 있습니까?

이 코드는 여러 아키텍처에서 작동하도록 선전되었지만 (모두 기억할 수는 없으며, 내 앞에 메이크 파일이 없음) 적어도 x86, amd64, itanium, arm7이 있습니다.

감사합니다.

편집 : 실제 상황에서 더 많은 스레드가 성공 변수에 쓸 수 있기 때문에 예제를 수정했습니다.

+1

출처가 명확하지 않습니까? "스레드 생성 및 구조는 동기화 작업으로 정의되므로 스레드 결합은 필연적으로 해당 스레드가 종료 된 후에 발생하므로 스레드가 종료되기 전에 반드시 발생하는 모든 사항을 볼 수 있습니다." –

+0

http : //en.cppreference에서 볼 수 있듯이 이후 확실하지 않습니다.co.kr/w/cpp/atomic/atomic_thread_fence 참조는 울타리와 원자 물체 간의 동기화만을 언급하며 펜스와 일반 객체 간의 동기화에 대해서는 아무 것도 없습니다. 내 생각에 조인은 그런 울타리를 내부적으로 사용한다고 생각하지만 틀릴 수도 있습니다. – Mikaka

+1

[예] (https://timsong-cpp.github.io/cppwp/thread.thread.member#4). 그렇지 않으면'join'은 오히려 쓸모가 없다. –

답변

1

위의 코드는 데이터 경쟁을 나타내며 join을 사용하면이 사실을 변경할 수 없습니다. 하나의 쓰레드 만 변수에 쓰는다면 괜찮을 것입니다. 하지만 두 개의 쓰레드가 있습니다. 입니다. 그것은 데이터 경주입니다.

join은 "해당 스레드의 모든 부작용이 완료되어 이제는 사용자에게 표시됩니다."라는 의미입니다. 그 스레드와 스레드 간의 순서 또는 동기화를 생성하지 않습니다 기타 자신의 것보다.

atomic_bool을 사용한 경우 UB가 아닐 수 있습니다. 거짓이라고 보장 될 것입니다. 그러나 데이터 경주가 있기 때문에 순수한 UB를 얻을 수 있습니다. 그것은 진실하거나, 거짓이거나, 비강의 악마 일 수 있습니다.

+0

알 수없는 동작 부분이 있습니다. 그러나 우리가 bool에 대한 쓰기가 원자 적이며 플랫폼 (즉, 모든 작업자와 결합하는 스레드)이 * success * 플래그를 읽는 유일한 플랫폼이라면 적절한 순서를 보장하기에 충분할 것입니다. 일부 작업자가 설정했거나 여전히 * true *를 얻을 수 있으면 항상 * false *를 참조하십시오. – Mikaka

+0

@Mikaka : "그러나 우리는 bool에 쓰기가 원자 단위 인 플랫폼에 있다고 가정합니다."아니오. C++에 대해 물었습니다. C++이 보장하는 것을 말하고 있습니다. 내가 바라는 임의의 플랫폼이 합리적인 것을 어떻게 수행하는지는 당신과 선택한 플랫폼 사이의 문제입니다. 이것을 * 보장 *하고 싶다면 실제 원자''를 사용하십시오. 그것이 당신이 생각하는 방식대로 행동하는 플랫폼이라면,'원자 '은'bool'을 감싸는 얇은 래퍼 일 것입니다. 그리고 그렇지 않다면 여전히 올바른 것입니다. –