2012-04-27 3 views
2

스레드 동시성 할당을 위해 std :: thread를 선택하여 실수를했습니다. 나는 다른 어떤 방법을 배울 시간이 없다. 그래서 당신이 저를 여기서 도울 수 있기를 바랍니다. 나는 mutexes, promises, futures 등 모든 유형에 대해 정말로 혼란스러워합니다. 다양한 문서/튜토리얼의 부족은 우울합니다. 그래서 3 개의 스레드 (플레이어)가 동일한 작업을 수행하기를 원합니다. 전역 2 차원 배열의 인덱스로 2 개의 난수를 선택하고, 셀의 값이 0이면 스레드의 ID와 같게 설정하고 그렇지 않으면 실. 스레드가 하나만 남을 때까지 반복하십시오. 내가 필요로하는 것은 3 개의 스레드를 매번 (다음에 가기 전에) 반복하는 방법을 찾아서 하나의 스레드가 50 번째 반복에있을 수없고 다른 하나는 30 번째에있을 수 없다는 것, 즉 스레드는 계속 진행하기 전에 모든 다른 사람들이 반복을 완료 할 때까지 기다리십시오. 나는 어떤 종류의 장벽이 필요합니다. 마지막 종료 스레드가 깨어 신호를 낼 때까지 스레드를 잠자기 상태로 놓으려고 시도했지만 상태가 정상적으로 작동하지 않습니다. 나는 모든 반복에 (먼저 도래) 하나의 스레드에 의해 실행되는 "call_once"것은 내부의 표현을 기대루프 내에서 C++ std :: thread synchronization

std::mutex GridMutex, FinishMutex, LeftMutex; 
int Grid[X][Y], Finished = 0, PlayersLeft = 3; 

void Fight(int Id) { 
    int RandX, RandY, i = 0; 
    std::random_device rd; // access random device 
    std::mt19937 e(rd()); // seed the engine 
    std::uniform_int_distribution<int> r1(0, X-1); 
    std::uniform_int_distribution<int> r2(0, Y-1); 
    LeftMutex.lock(); // mutex on PlayersLeft 
    while (PlayersLeft != 1) { 
    ++i; 
    /*std::call_once(flag, [Id, i](){*/std::cout << " Round " << i << " Left: " << PlayersLeft << '\n';/*});*/ 
    LeftMutex.unlock(); 
//  FinishMutex.lock(); 
//  std::call_once(flag, [](){Finished = 0;}); 
//  FinishMutex.unlock(); 
    RandX = r1(e); 
    RandY = r2(e); 
    GridMutex.lock(); 
    if (Grid[RandX][RandY] != Id) { 
     if (Grid[RandX][RandY] == 0) { 
     Grid[RandX][RandY] = Id; 
     std::cout << "i= "<< i << " Thread " << Id << " occupied cell " << RandX << RandY << '\n'; 
     std::chrono::milliseconds sleepDuration(100); 
     std::this_thread::sleep_for(sleepDuration); //just to lock the grid for some time 
     GridMutex.unlock(); 
     } 
     else { 
     GridMutex.unlock(); 
     LeftMutex.lock(); 
     --PlayersLeft; 
     LeftMutex.unlock(); 
     break; //stop thread if cell occupied 
     } 
    } 
    //Wait for the others here 
//  FinishMutex.lock(); 
//  ++Finished; 
//  if (Finished == 3) { 
//  FinishMutex.unlock(); 
//  AllReady.notify_all(); 
//  } 
//  else { 
//  FinishMutex.unlock(); 
//  AllReady.wait(Lk, [](){return Finished == 3;}); 
//  Lk.unlock(); 
//  } 
    LeftMutex.lock(); 
    } 
} 
int main() { 
    SetGrid(); 
    std::thread t1(&Fight, 1); 
    std::thread t2(&Fight, 2); 
    std::thread t3(&Fight, 3); 
    t1.join(); 
    t2.join(); 
    t3.join(); 
    GetGrid(); 
    return 0; 
} 

하지만 obiviously 내가 그것 때문에 무슨 생각이 아니다 : 내 실패한 시도가 주석 처리되어 그것은 이상한 행동을 초래합니다. 그렇게하는 방법? 자, 코드가 추악 할 수도 있고 클래스와 메소드 또는 다른 것들 안에 넣어 두어야 할 수도 있습니다. 그러나이 코드는 아무리 중요하게 생각해도됩니다. 미리 감사드립니다.

+0

이렇게하면 3 개의 스레드가 배열의 요소를 임의로 선택하도록하고, 0이 아닌 경우 스레드가 끝나고 그렇지 않으면 다시 시도하고 모든 스레드가 하나가 될 때까지 동기화하려고합니다 ? – 111111

+7

'std :: thread'를 실수로 사용하지 않았습니다. 기본 멀티 스레딩을 이해하지 못했던 실수를 저 지르 셨습니다. – jalf

+0

예.하지만 0이 아니지만 Id와 같으면 아무것도하지 않으면 다음 반복으로 건너 뜁니다. – andrisll

답변

1

당신은 잠금을하지 않는 것과

다음. std::atomic_intstd::atomic_bool (또는 std::atomic_flag 같은 atomic variables를 사용하여 일부 잠금을 제거하고 자신의 잠금을 해제하지만 std::lock_guard처럼,이에 대한 RAII 래퍼를 사용할 수 있습니다.이 잠 깁니다 잠금 객체 자체가 파괴 될 때까지 지정된 뮤텍스 (대개 범위를 벗어날 때)

이제 이러한 것들을 사용하면 코드가 크게 향상되지만 실제 논리 오류는 매우 간단합니다. 상수 3이 아니라 playersLeft입니다. 조건은 이것에 의존합니다.이 변수를 변경할 때마다 신호를 보내야합니다.

+0

LeftMutex 및 FinishMutex를 제거 할 수 있습니까? 그리고 GridMutex가 아닌가? 그래서 PlayerLeft int를 바꾼다. std :: 원자 으로 끝냈다. 그러나 비교, 변경 또는 가치를 얻으려면 store, load 및 compare_exchange 함수를 사용해야합니까? 나는 그렇지 않다. 첫 번째 "if"문 앞에 lock_guard를 배치하고 GridMutex를 제거 할 수 있습니까? 전체 "if"블록 이후에 잠금 해제됩니까? 예, 플레이어를 알고 있었지만 오류가 발생했습니다. 수정하는 것을 잊어 버렸습니다. – andrisll

+0

그 call_once는 어떨까요? 고마워, 너 나 좀 도와 줘! – andrisll

+0

@ user1079355 : 정수 자체와 마찬가지로 대부분의 숫자 원자형을 사용할 수 있습니다. 할당,'+','++', ... 등의 연산자는이 목적을 위해 오버로드됩니다.범위가 지정된 잠금은 범위를 벗어난 후에 제거되므로 잠금 해제 전에 잠금을 해제하면 잠금이 해제됩니다. if (if 문 자체 포함)를 원하면 '{}'을 사용하여 새 범위를 도입하면됩니다. 범위 기반 경비원의 장점은 '던지기, 꺾기, 되찾기'와 같은 일을하면 혼란을 없앨 수 있다는 것입니다. – KillianDS

관련 문제