2009-05-22 3 views
3

전역 변수, 시간 currentTime을 가진 Foo 개체가 있습니다C++ 스레딩 질문

Foo는 다른 스레드에서 호출되는 두 가지 방법이 있습니다.

update() 
{ 
    currentTime = currentTime + timeDelay; 
} 

restart(Time newTime) 
{ 
    currentTime = newTime; 
} 

내가 다시 시작에 행동을보고하고, 시간이 currentTime을 재설정하지 않는 것 (또는 재설정 않고 어떻게 든 다시 세트에게 그것을 업데이트 곳 정확하고 다른 시간으로 변경합니다.

방법 업데이트입니다 사용자가 재시작 이벤트 (버튼을 누름)를 시작할 때만 재시작하는 동안 발생합니다.이 문제는 스레딩 타이밍 문제이며, 어떤 일이 일어나고 있는지에 대한 제안이나 의견은 언제든지 환영합니다.

답변

9

여기서 가장 경쟁이 치열한 해결책은 공유 변수 012의 사용을 보호하는 것입니다자물쇠를 사용하여. 나는 여기에 Boost.Threads 뮤텍스 클래스를 사용하고 있습니다 :

class Foo 
{ 
    boost::mutex _access; 
    update() 
    { 
    boost::mutex::scoped_lock lock(_access); 
    currentTime = currentTime + timeDelay; 
    } 

    restart(Time newTime) 
    { 
    boost::mutex::scoped_lock lock(_access); 
    currentTime = newTime; 
    } 
}; 
0

는 무슨 일이 일어나고 있는지의 로그를 생성하는 각 기능의 일부 printfs를 추가합니다.

예를 들어, "currentTime = newTime;"직후 다른 스레드에서 update()가 실행되면 어떻게 될 것으로 예상됩니까? - 또는 심지어 악화 - 그 라인의 과제에서 동안. 당신이 그 일을 한 후에

는, 한 번 봐 가지고 : 두 개의 스레드에서 같은 변수를 (당신이하고있는 것처럼) 액세스 http://en.wikipedia.org/wiki/Mutual_exclusion

0

은 동기화 해 어떤 종류의가 필요합니다. 하나의 스레드 즉, 한 번에 그 변수에 액세스하고 있음을 수익을 창출하기 위해 뮤텍스를 사용

update() 
{ 
    // Lock mutex 
    currentTime = currentTime + timeDelay; 
    // unlock mutex 
} 
// Same idea for restart() 

문제는 같은 변수에 대한 액세스이다, 프리미티브 동기화 해없이 같은 뮤텍스로, 스레드 문제가있다. 업데이트()는 currentTime을 읽고, 더하기를 수행하지만, 결과를 저장할 수 있기 전에 스레드를 전환한다고하자. restart()는 그 일을한다. 이제 우리는 다시 update()로 돌아가서, 현재 유효하지 않은 결과를 currentTime에 다시 쓰고 restart()의 작업을 덮어 씁니다. 뮤텍스 (Mutex)는 당신에게 수술이 원자적임을 허용함으로써 이것을 방지합니다. Google에서는 자습서를 위해 교착 상태와 같은 많은 정보를 알아야합니다.

정확히 뮤텍스를 생성/잠금하는 방법은 사용하려는 OS/라이브러리에 따라 다릅니다. 네이티브 솔루션은 * nix 시스템의 pthreads, Win32의 Critical 섹션입니다. (pthreads 구현은 Win32 용으로 존재합니다.) Boost 라이브러리에는 스레드 섹션도 있습니다.

1

스레드 1 호출 업데이트, currentTime 사본을 가져 와서 스레드 로컬 메모리에 저장합니다. 스레드 2가 다시 시작되면 currentTime을 newTime으로 설정합니다. 스레드 2 완료. 스레드 1이 계속 진행되고 스레드 로컬 메모리 (재시작 호출 이전의 currentTime의 이전 값) + timeDelay에서 currentTime을 currentTime에 재 할당합니다. 스레드 1이 이제 완료됩니다.

따라서 다시 시작하지 못했습니다. 발생할 수있는 많은 다른 상황이 예기치 않은 동작을 일으킬 수 있습니다. 이러한 문제를 피하려면 다른 스레드간에 공유 된 변수를 항상 동기화하십시오.

다른 사람이 제안한 뮤텍스를 사용해야합니다.

0

뮤텍스를 사용하면이 상황에서 너무 무거워 보입니다.대신 InterlockedExchange와 InterlockedAdd를 사용합니다.

0

중요한 영역을 입력하는 동안 잠금이없고 각각이 current_time을 업데이트하기 때문에 경쟁 조건이 있습니다. 각 스레드는 메모리를 가지고 있는데, 스레드가 공유 메모리에서 무엇인가를 얻어야 할 때 스레드는 이것을 로컬 메모리에 복사합니다. 첫 번째 단계는 잠금을 먼저 얻은 다음 변수를 공유 메모리에서로드 할 수 있도록 메모리를 지우는 것입니다. 이제 중요한 영역에서 작동하고 일단 지역 변수가 공유 메모리에 쓰여지도록 보장하는 중요한 영역의 잠금을 해제합니다. 자물쇠가 없으므로 어떤 일이 일어날 지 예측할 수 없습니다.

뮤텍스를 사용하면 current_time 변수에 키가 하나만 있으므로 사례에 필요한 것입니다. 다른 유형의 잠금은 다중 키를 허용하는 세마포어입니다. 당신이 말하는 것처럼 currentTime을가 정말 전역 변수 경우

0

, 당신은 변수를 보호하기 위해 글로벌 뮤텍스 필요합니다. (PTHREAD_MUTEX_INITIALIZER 또는 BOOST.call_once 구성)

다른 스레드에있는 Foo 클래스의 두 인스턴스가 _access 뮤텍스의 다른 인스턴스를 갖기 때문에 BOOST.Threads 예제가 올바르지 않습니다. (사실은 _ prefex를 선호하지 않습니다. !) 자신의 인스턴스를 잠그고 currentTime 변수를 보호하지 않습니다.

currentTime이 인스턴스 변수 인 경우 BOOST.Threads 예제가 정확합니다.