나는 여러 작업자 스레드를 시작하는 함수를 가지고 있습니다. 각 작업자 스레드는 객체에 의해 캡슐화되고 해당 객체의 소멸자는 스레드 을 호출하여 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되는 경우 모두 몇 가지 코드를 실행하거나 플래그 및 조건 변수 조합 대신 작업자를 깨우는 더 나은 메커니즘을 제공해야합니다.
작업을 완료 할 수있는 큐를 사용하지 말고 스레드를 차단하지 않는 이유는 무엇입니까? 그런 다음 주기적으로 대기열을 확인하고 필요한 비트가 들어 있는지 확인하고 계속 진행할 수 있습니다. –
'FinallyGuard' (아마도'on_scope_exit() '라고 부르는 것 같습니다. 그러나 그것은 맛의 문제입니다)는 나에게 좋습니다. 그러나 이것은'manageWork()'의 범위가 종료 될 때마다 호출된다는 것을 알아 두십시오. 예외가 던져지기 때문에뿐만 아니라 일반적인'return's에 대해서조차도 마찬가지입니다. –
@AndyProwl 그것은'try ... finally' 문의 일반적인 의미입니다. – didierc