2013-03-05 6 views
0

나는 여러 작업자 스레드를 시작하는 함수를 가지고 있습니다. 각 작업자 스레드는 객체에 의해 캡슐화되고 해당 객체의 소멸자는 스레드 을 호출하여 join을 시도합니다. 그러나 각 근로자가 얼마나 많은 노동을 수행해야하는지는 선험적으로 알려지지 않았습니다. 관리 기능은 뮤텍스와 조건 변수를 사용하여 스레드에 작업 단위를 할당합니다. 더 이상 할 일이 없으면 뮤텍스가 보류 중일 때 특정 플래그가 설정된 다음 조건 변수에서 차단 된 모든 스레드에 통보되어 변경된 플래그를 확인하고 종료합니다.근로자 종료

메인 스레드에 예외가 있어도이 종료가 작동되기를 원합니다. Java에서 finally 절을 에 항상 사용하면 플래그를 설정하고 작업 처리 루프의 끝에서 스레드에 알립니다. C++ doesn't have finally, 나는 내 자신의 교체 썼다 :

class FinallyGuard { 
private: 
    std::function<void()> f_; 
public: 
    FinallyGuard(std::function<void()> f) : f_(f) { } 
    ~FinallyGuard() { f_(); } 
}; 

void Manager::manageWork(unsigned NumWorkers) { 
    // Order matters: destructors are called in reverse order and will 
    // 1. release the mutex lock so that workers can proceed 
    // 2. unblock all threads using the finally workalike 
    // 3. destroy the workers and join their threads 
    std::forward_list<Worker> workers; 
    FinallyGuard signalEndGuard([this] { 
    std::unique_lock<std::mutex> lk(mtx_); 
    done_ = true; 
    beginWork_.notify_all(); 
    }); 
    std::unique_lock<std::mutex> lk(mtx_); 
    for (unsigned i = 0; i != numWorkers; ++i) 
    workers.emplace_front(this); 
    while (haveMoreWork()) { 
    // … 
    } 
} 

을하지만 분명히 여기에 다른 언어의 개념에서 생각하고 있어요. 더 많은 C++과 같은 방법으로 이것을 구현할 수 있습니까? 솔루션은 메서드에서 정상적인 반환과 예외가 throw되는 경우 모두 몇 가지 코드를 실행하거나 플래그 및 조건 변수 조합 대신 작업자를 깨우는 더 나은 메커니즘을 제공해야합니다.

+0

작업을 완료 할 수있는 큐를 사용하지 말고 스레드를 차단하지 않는 이유는 무엇입니까? 그런 다음 주기적으로 대기열을 확인하고 필요한 비트가 들어 있는지 확인하고 계속 진행할 수 있습니다. –

+1

'FinallyGuard' (아마도'on_scope_exit() '라고 부르는 것 같습니다. 그러나 그것은 맛의 문제입니다)는 나에게 좋습니다. 그러나 이것은'manageWork()'의 범위가 종료 될 때마다 호출된다는 것을 알아 두십시오. 예외가 던져지기 때문에뿐만 아니라 일반적인'return's에 대해서조차도 마찬가지입니다. –

+0

@AndyProwl 그것은'try ... finally' 문의 일반적인 의미입니다. – didierc

답변

1

최종적으로 동등한 기능이 C++에 존재하지만 코어 언어는 아닙니다. 이것은 C++ 필드의 "록 스타"중 하나 인 Andrej Alexandrescu가 만든 ScopeGuard라고합니다. 여기에 그가 C++에서 더 중요하게 여기 컨퍼런스 2012 http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C

넘어서 새로운 버전을 선물하는 코드입니다 : https://gist.github.com/KindDragon/4650442

귀하의 예를 거의 같은 일을한다. ScopeGuard라고 부르거나 Alexandrescus 코드를 사용해야합니다. 다른 C++ 프로그래머가 무엇을 의미하는지 알고 싶으면 Alexandrescus 코드를 사용해야합니다.이 코드는 라이브러리 나 공통 포함에 자주 사용해야합니다. C++ 프로그래머는 RAII를 모든 것에 사용할 수 있습니다. 내 생각에는 의도적으로 표현하려는 의도가 중요합니다.

SCOPE_EXIT { 
    std::unique_lock<std::mutex> lk(mtx_); 
    done_ = true; 
    beginWork_.notify_all(); 
}; 

귀하의 경우에는 매우 유용합니다.

내가 일하는 곳 ScopeGuard는 좋은 스타일로 간주되며 코드 검토를 통과합니다. 상업적으로 사용하려는 경우 공개 된 것입니다.

0

C++ 방법은 RAII이라는 것을 사용하는 것입니다. 소멸자는 항상 호출되어 일부 코드가 항상 실행되도록한다는 사실을 사용합니다.

+0

그리고 RAII를 사용하여 다른 관용어를 모델로 만들었고 다른 언어로 그 모델을 만들었고 내가 옳은 일을하는지 궁금해했습니다. 위에서 보았 듯이, 위의 예제는 소멸자를 사용하여 물건을 처리하지만, RAII의 "자원"이 실제로 무엇인지, 또는 정확히 그것이 획득 된 곳을 설명하는 것은 어렵습니다. 그래서 저는 RAII의 구현 기술을 사용하고 있습니다.하지만 실제로 그 모델링 아이디어는 아닙니다. – MvG