Уволить работников

У меня есть функция, которая запускает несколько рабочих потоков. Каждый рабочий поток инкапсулирован объектом, и деструктор этого объекта попытается join нить, т.е. if (thrd_.joinable()) thrd_.join();, Но априори неизвестно, сколько работы придется выполнять каждому работнику. управляющая функция назначает рабочие потоки потокам, используя мьютекс и переменную условия. Если больше не нужно выполнять никаких действий, то во время удержания мьютекса устанавливается определенный флаг, а затем все потоки, заблокированные в переменной условия, получают уведомление, чтобы они проснулись, заметили измененный флаг и закрылись.

Я хочу, чтобы это отключение работало, даже если в главном потоке есть исключение. В Java я бы использовал finally пункт к всегда установите флаг и уведомите потоки в конце цикла обработки работы. Как C ++ не имеет 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 ++-подобный способ добиться этого? Решение должно было бы либо выполнить некоторый код как для нормального возврата из метода, так и для случая, когда выдается исключение, или предоставить какой-то лучший механизм для пробуждения работников вместо комбинации флаг и переменная условия.

0

Решение

Эквивалентная попытка наконец существует в C ++, хотя и не в базовом языке. Он называется ScopeGuard, изначально созданный Андреем Александреску, одной из «рок-звезд» в области C ++. Здесь он представляет новую версию на конференции C ++ и Beyond 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 ++ поняли, что вы имеете в виду. Программисты C ++ используют RAII для всего, на мой взгляд, важно выразить намерение, что довольно хорошо

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

в твоем случае.

Где я работаю, ScopeGuard считается хорошим стилем и проходит проверку кода просто отлично. Это также общественное достояние, если вы хотите использовать его в коммерческих целях.

1

Другие решения

C ++ способ состоит в том, чтобы использовать то, что называется RAII. Вы используете тот факт, что деструкторы всегда вызываются, чтобы гарантировать, что некоторый код всегда выполняется.

0

По вопросам рекламы [email protected]