Condition_variable c++
Есть простой пример использования Condition_variable:
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
int global_status = 0;
void print_id(int id)
{
std::unique_lock<std::mutex> lck(mtx);
while (global_status == 0)
{
cv.wait(lck);
}
std::cout << "thread " << id << '\n';
}
int main()
{
std::thread threads[10];
for (int i = 0; i < 10; ++i)
{
threads[i] = std::thread(print_id, i);
}
std::cout << "Start" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5)); //Пауза, чтобы убедится, что потоки в ожидании.
{
std::unique_lock<std::mutex> lck(mtx);
global_status = 1;
cv.notify_all();
}
for (auto& th : threads) th.join();
return 0;
}
Я все таки до сих пор не могу понять, зачем блокировать переменную global_status, когда я меняю ее значение ?
Ответы (2 шт):
Между просмотром о состоянии переменной и командой ожидании сигнала находится критический участок кода.
Если поток ждёт сигнал, который был выслан до команды wait, то этот сигнал к нему так и не придёт. И будет ждать вечно. Сигнал получат только те процессы, что ждали его. А те процессы, что не успели встать в очередь будут ждать второго сигнала.
| while (global_status == 0)
global_status = 1; |
cv.notify_all(); |
| cv.wait(lck); вечно
В примере не зря поставили задержку 5 секунд. Без неё сигналы получат те, кто успел. А блокирование для отправки сигнала препятствует хотя-бы такой ситуации.
В реальных программах, сначала ставиться мютекс, проверяется флаг, что процесс ждёт сигнал, и потом если надо - отправляет. Только потом освобождается мютекс. Без блокировки будет неразбериха.
Condition работает следющим образом:
при вызове
.wait(mtx), переданный mutex освобождается, тем самым давая работать какому-то из потоков, ждущих указанного mutex-а, а сам thread приостанавливается.при вызове
.notyfy_all()все потоки, приостановленные на condition variable, пробуждаются и тут же пытаются захватить mutex, который связан с этой переменной. Одному из них это удается и он возвращается из .wait() с захваченным mutex.
Т.е. mutex передаваемый в .wait() нужен для обеспечения сериализации работы потоков.
Возможно понимание этих мезанизмов будет лучше, если почитать документацию, например, по pthreads (обычно лежащих в основе С++ multithreading)