Класс<condition_variable>обеспечивает механизм для волокна, чтобы ждать уведомления от другого волокна. Когда клетчатка пробуждается от ожидания, она проверяет, является ли соответствующее состояние верным, и продолжается, если это так. Если это не так, то волокно снова вызывает<wait>, чтобы возобновить ожидание. В простейшем случае это условие является просто булевой переменной:
Обратите внимание, что<lk>передается.<condition_variable::wait()>:<wait()>атомарно добавит волокно к набору волокон, ожидающих переменную состояния, и разблокирует.<mutex>. После того, как волокно пробуждается,<mutex>снова запирается перед призывом<wait()>. Это позволяет другим волокнам получать<mutex>для обновления общих данных и гарантирует, что данные, связанные с состоянием, правильно синхронизированы.
wait_for_data_to_process() could equivalently be written:
voidwait_for_data_to_process(){{std::unique_lock<boost::fibers::mutex>lk(mtx);// make condition_variable::wait() perform the loopcond.wait(lk,[](){returndata_ready;});}// release lkprocess_data();}
Блокировка важна, потому что объекты синхронизации, предоставляемыеBoost.Fiber, могут использоваться для синхронизации волокон, работающих на разных нитях.
Но данное потребительское волокно вполне может проснуться от<condition_variable::wait()>и найти очередь<empty()>, потому что другие потребительские волокна, возможно, уже обработали все отложенные предметы.
Все волокна, ожидающие<*this>, были уведомлены звонком<notify_one>или<notify_all>(хотя соответствующие звонки на<wait>,<wait_for>или<wait_until>не обязательно возвращались).
Если какие-либо волокна в настоящее времязаблокированы, ожидая<*this>в вызове<wait>,<wait_for>или<wait_until>, разблокирует все эти волокна.
Throws:
Ничего.
Note:
Вот почему ожидающее волокно должнотакжепроверять желаемое состояние программы с помощью механизма, внешнего по отношению к<condition_variable_any>, и повторять ожидание до достижения этого состояния. Волокно, ожидающее<condition_variable_any>, может проснуться несколько раз до достижения желаемого состояния.
<lk>запирается текущим волокном, и либо никакое другое волокно в настоящее время не ожидает<*this>, либо выполнение.<mutex()>Функция элемента на<lk>объектах, подаваемых в вызовах на<wait>во всех волокнах, в настоящее время ожидающих на<*this>, возвращала бы то же значение, что и<lk->mutex()>для этого вызова на<wait>.
Effects:
Атомно вызывает<lk.unlock()>и блокирует текущее волокно. При звонке<this->notify_one()>или<this->notify_all()>волокно разблокируется. Когда волокно разблокировано (по какой-либо причине), замок вновь приобретается путем вызова<lk.lock()>до того, как призыв к<wait>вернется. Замок также приобретается путем вызова<lk.lock()>, если функция выходит за исключением. Функция члена, принимающая<pred>, является сокращением для:
while(!pred()){wait(lk);}
Postcondition:
<lk>запирается текущим волокном.
Throws:
<fiber_error>Если произошла ошибка.
Note:
Предварительное условие немного плотное. Он просто утверждает, что все волокна, одновременно вызывающие<wait>на<*this>, должны ждать на<lk>объектах, управляющихтем же<mutex>. В любом вызове<condition_variable_any::wait()>участвуют три различных объекта: сам<condition_variable_any>,<mutex>координирующий доступ между волокнами и локальным объектом блокировки (например,<std::unique_lock>). В общем, можно разделить продолжительность жизни данного случая<condition_variable_any>на периоды с одним или несколькими волокнами, ожидающими его, разделенными периодами, когда волокна не ждут его. Когда на этом<condition_variable_any>ожидает более одного волокна, все должны пройти блокировки объектов, ссылаясь натот же<mutex>экземпляр.
<lk>запирается текущим волокном, и либо никакое другое волокно в настоящее время не ожидает<*this>, либо выполнение функции члена<mutex()>на объектах<lk>, подаваемых в вызовах на<wait>,<wait_for>или<wait_until>во всех волокнах, ожидающих в настоящее время на<*this>, возвращает то же значение, что и<lk.mutex()>для этого вызова на<wait_until>.
Effects:
Атомно вызывает<lk.unlock()>и блокирует текущее волокно. Волокно разблокируется, когда оно будет уведомлено вызовом<this->notify_one()>или<this->notify_all()>, когда системное время будет равно или позже указанного<abs_time>. Когда волокно разблокировано (по какой-либо причине), замок вновь приобретается, призывая<lk.lock()>до того, как призыв к<wait_until>вернется. Замок также приобретается путем вызова<lk.lock()>, если функция выходит за исключением. Функция члена, принимающего<pred>, является сокращением для:
То есть, даже если<wait_until()>раз нет, он все равно может вернуться<true>, если<pred()>вернется<true>в то время.
Postcondition:
<lk>запирается текущим волокном.
Throws:
<fiber_error>при возникновении ошибки или исключений, связанных с тайм-аутом.
Returns:
Перегрузка без<pred>возвращается<cv_status::no_timeout>при пробуждении<notify_one()>или<notify_all()>, или<cv_status::timeout>при пробуждении, потому что системное время прошло<abs_time>.
Returns:
Перегрузка, принимающая<pred>, возвращается<false>, если звонок возвращается, потому что было достигнуто время, указанное<abs_time>, и предикат возвращается<false>,<true>в противном случае.
<lk>блокируется текущим волокном, и либо никакое другое волокно в настоящее время не ожидает<*this>, либо выполнение функции члена<mutex()>на объектах<lk>, подаваемых в вызовах<wait>,<wait_for>или<wait_until>во всех волокнах, ожидающих в настоящее время<*this>, вернуло бы то же значение, что и<lk.mutex()>для этого вызова<wait_for>.
Effects:
Атомно вызывает<lk.unlock()>и блокирует текущее волокно. Волокно разблокируется при уведомлении по телефону<this->notify_one()>или<this->notify_all()>, когда интервал времени, равный или превышающий указанный<rel_time>, истек. Когда волокно разблокировано (по какой-либо причине), замок вновь приобретается путем вызова<lk.lock()>до того, как призыв к<wait>вернется. Замок также приобретается путем вызова<lk.lock()>, если функция выходит за исключением. Функция<wait_for()>, принимающая<pred>, является сокращением для:
(За исключением того, что<rel_time>корректируется для каждой итерации). Но если бы он был в состоянии<wait_for()>, то он мог бы вернуться<true>, если бы<pred()>вернулся<true>в то время.
Postcondition:
<lk>запирается текущим волокном.
Throws:
<fiber_error>при возникновении ошибки или исключений, связанных с тайм-аутом.
Returns:
Перегрузка без<pred>возвращается<cv_status::no_timeout>, если она пробудилась<notify_one()>или<notify_all()>, или<cv_status::timeout>, если она пробудилась, потому что по крайней мере<rel_time>прошло.
Returns:
Перегрузка, принимающая<pred>, возвращается<false>, если звонок возвращается, потому что, по крайней мере,<rel_time>истек, а предикат возвращается<false>,<true>в противном случае.
Все волокна, ожидающие<*this>, были уведомлены звонком<notify_one>или<notify_all>(хотя соответствующие звонки на<wait>,<wait_for>или<wait_until>не обязательно возвращались).
Если какие-либо волокна в настоящее времязаблокированы, ожидая<*this>в вызове<wait>,<wait_for>или<wait_until>, разблокирует все эти волокна.
Throws:
Ничего.
Note:
Вот почему ожидающее волокно должнотакжепроверять желаемое состояние программы с помощью механизма, внешнего по отношению к<condition_variable>, и повторять ожидание до достижения этого состояния. Волокно, ожидающее<condition_variable>, может проснуться несколько раз до достижения желаемого состояния.
<lk>запирается текущим волокном, и либо никакое другое волокно в настоящее время не ожидает<*this>, либо выполнение.<mutex()>Функция элемента на<lk>объектах, подаваемых в вызовах на<wait>во всех волокнах, в настоящее время ожидающих на<*this>, возвращала бы то же значение, что и<lk->mutex()>для этого вызова на<wait>.
Effects:
Атомно вызывает<lk.unlock()>и блокирует текущее волокно. При звонке<this->notify_one()>или<this->notify_all()>волокно разблокируется. Когда волокно разблокировано (по какой-либо причине), замок вновь приобретается путем вызова<lk.lock()>до того, как призыв к<wait>вернется. Замок также приобретается путем вызова<lk.lock()>, если функция выходит за исключением. Функция члена, принимающая<pred>, является сокращением для:
while(!pred()){wait(lk);}
Postcondition:
<lk>запирается текущим волокном.
Throws:
<fiber_error>Если произошла ошибка.
Note:
Предварительное условие немного плотное. Он просто утверждает, что все волокна, одновременно вызывающие<wait>на<*this>, должны ждать на<lk>объектах, управляющихтем же<mutex>. В любом вызове<condition_variable::wait()>участвуют три различных объекта: сам<condition_variable>,<mutex>координирующий доступ между волокнами и локальным объектом блокировки (например,<std::unique_lock>). В общем, можно разделить продолжительность жизни данного экземпляра<condition_variable>на периоды с одним или несколькими волокнами, ожидающими его, разделенными периодами, когда волокна не ждут его. Когда этого<condition_variable>ожидает более одного волокна, все должны пройти блокировку объектов, ссылаясь натот же<mutex>экземпляр.
<lk>запирается текущим волокном, и либо никакое другое волокно в настоящее время не ожидает<*this>, либо выполнение функции члена<mutex()>на объектах<lk>, подаваемых в вызовах на<wait>,<wait_for>или<wait_until>во всех волокнах, ожидающих в настоящее время на<*this>, возвращает то же значение, что и<lk.mutex()>для этого вызова на<wait_until>.
Effects:
Атомно вызывает<lk.unlock()>и блокирует текущее волокно. Волокно разблокируется, когда оно будет уведомлено вызовом<this->notify_one()>или<this->notify_all()>, когда системное время будет равно или позже указанного<abs_time>. Когда волокно разблокировано (по какой-либо причине), замок вновь приобретается, призывая<lk.lock()>до того, как призыв к<wait_until>вернется. Замок также приобретается путем вызова<lk.lock()>, если функция выходит за исключением. Функция члена, принимающего<pred>, является сокращением для:
То есть, даже если<wait_until()>раз нет, он все равно может вернуться<true>, если<pred()>вернется<true>в то время.
Postcondition:
<lk>запирается текущим волокном.
Throws:
<fiber_error>при возникновении ошибки или исключений, связанных с тайм-аутом.
Returns:
Перегрузка без<pred>возвращается<cv_status::no_timeout>при пробуждении<notify_one()>или<notify_all()>, или<cv_status::timeout>при пробуждении, потому что системное время прошло<abs_time>.
Returns:
Перегрузка, принимающая<pred>, возвращается<false>, если звонок возвращается, потому что было достигнуто время, указанное<abs_time>, и предикат возвращается<false>,<true>в противном случае.
<lk>блокируется текущим волокном, и либо никакое другое волокно в настоящее время не ожидает<*this>, либо выполнение функции члена<mutex()>на объектах<lk>, подаваемых в вызовах<wait>,<wait_for>или<wait_until>во всех волокнах, ожидающих в настоящее время<*this>, вернуло бы то же значение, что и<lk.mutex()>для этого вызова<wait_for>.
Effects:
Атомно вызывает<lk.unlock()>и блокирует текущее волокно. Волокно разблокируется при уведомлении по телефону<this->notify_one()>или<this->notify_all()>, когда интервал времени, равный или превышающий указанный<rel_time>, истек. Когда волокно разблокировано (по какой-либо причине), замок вновь приобретается путем вызова<lk.lock()>до того, как призыв к<wait>вернется. Замок также приобретается путем вызова<lk.lock()>, если функция выходит за исключением. Функция<wait_for()>, принимающая<pred>, является сокращением для:
(За исключением того, что<rel_time>корректируется для каждой итерации). Но если бы он был в состоянии<wait_for()>, то он мог бы вернуться<true>, если бы<pred()>вернулся<true>в то время.
Postcondition:
<lk>запирается текущим волокном.
Throws:
<fiber_error>при возникновении ошибки или исключений, связанных с тайм-аутом.
Returns:
Перегрузка без<pred>возвращается<cv_status::no_timeout>, если она пробудилась<notify_one()>или<notify_all()>, или<cv_status::timeout>, если она пробудилась, потому что по крайней мере<rel_time>прошло.
Returns:
Перегрузка, принимающая<pred>, возвращается<false>, если звонок возвращается, потому что, по крайней мере,<rel_time>истек, а предикат возвращается<false>,<true>в противном случае.
Статья Condition Variables раздела Chapter 1. Fiber Synchronization может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.