C ++. std :: condition_variable и несколько потоков ожидания - PullRequest
2 голосов
/ 01 августа 2020

У меня есть класс с queue из std::function<void()> члена и методов Push и Pop.

Я хочу реализовать метод сложения PushAndWaitUntilExecuted. Это просто, когда у вас есть один consumer-thread (звонящий Pop) и один producer-thread (тот, кто звонит Push) - достаточно простого std::condition_variable.

Но в моем приложении есть динамика c количество потоков, которые могут выполнять одни и те же строки кода при параллельном вызове функции PushAndWaitUntilExecuted и ждать, пока consumer-thread выполнит нажатый std::function объект.

Есть идея с передачей std::pair<uint64_t, std::function<void()>> на queue вместо std::function<void()>, где uint64_t - producer-thread ID (boost::this_thread::get_id()). Затем consumer-thread вызовет std::condition_variable::notify_all(), и все потоки будут проверять, выполнено ли std::function с тем же ID с потоком или нет.

Это нормально, решение или может быть реализовано что-то лучшее?

1 Ответ

2 голосов
/ 01 августа 2020

Здесь необходимо ввести больше, чем просто условную переменную, чтобы избежать нескольких различных состояний гонки. Также требуются мьютекс и флаг завершения задания.

На этом этапе становится проще заменить ваш std::function<void()> небольшим классом, который содержит это закрытие, а также весь дополнительный багаж:

struct job {
   std::function<void()> implementation;
   std::mutex m;
   std::condition_variable flag;
   bool completed=false;
};

Ваша очередь становится очередью std::shared_ptr<job> s вместо очереди std::function s, с заданиями, созданными в области динамической c (поскольку, конечно, мьютексы и переменные условия не копируются или подвижный, и эти объекты доступны из обоих ваших потоков).

После того, как ваш рабочий поток завершит выполнение реализации , он:

  1. блокирует мьютекс .
  2. устанавливает completed в значение true
  3. сигнализирует об условной переменной.

И ваш PushAndWaitUntilExecuted, после того, как он выполняет pu sh:

  1. блокирует мьютекс
  2. ожидает в переменной условия, пока не будет установлено completed

Вы должны полностью понимать, что C ++ не дает вам абсолютно никаких гарантий, вообще , что после пу sh новое закрытие в вашу очередь заданий, какой-то поток не сразу захватывает его, не выполняет и не завершает sh до того, как исходный поток (тот, который его подтолкнул) не успеет посмотреть на переменную условия. К настоящему времени никто больше не будет сигнализировать об условной переменной. Если все, с чем вам нужно работать здесь, это просто переменная условия, вы будете ждать, пока переменная условия не получит сигнал, пока наше солнце не взорвется.

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

Это довольно классический рутинный подход. Вы должны найти примеры многих подобных реализаций в каждом хорошем учебнике C ++ по этому предмету.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...