std:: call_once
|
Определено в заголовочном файле
<mutex>
|
||
|
template
<
class
Callable,
class
...
Args
>
void call_once ( std:: once_flag & flag, Callable && f, Args && ... args ) ; |
(начиная с C++11) | |
Выполняет Callable объект f ровно один раз, даже если вызов происходит параллельно из нескольких потоков.
Подробно:
-
Если к моменту вызова
std::call_onceфлаг flag указывает, что f уже была вызвана,std::call_onceнемедленно возвращает управление (такой вызовstd::call_onceназывается пассивным ).
-
В противном случае,
std::call_onceвызывает INVOKE ( std:: forward < Callable > ( f ) , std:: forward < Args > ( args ) ... ) . В отличие от конструктора std::thread или std::async , аргументы не перемещаются и не копируются, поскольку их не требуется передавать в другой поток выполнения (такой вызовstd::call_onceназывается активным ).
-
-
Если при вызове возникает исключение, оно передается вызывающей стороне
std::call_once, и flag не переключается, так что будет предпринята следующая попытка вызова (такой вызовstd::call_onceназывается исключительным ). -
Если вызов завершается нормально (такой вызов
std::call_onceназывается возвращающим ), flag переключается, и все остальные вызовыstd::call_onceс тем же flag гарантированно являются пассивными .
-
Если при вызове возникает исключение, оно передается вызывающей стороне
Все активные вызовы на одном и том же flag образуют единый полный порядок, состоящий из нуля или более исключительных вызовов, за которыми следует один возвращающий вызов. Конец каждого активного вызова синхронизируется-с началом следующего активного вызова в этом порядке.
Возврат из
возвращающего
вызова синхронизируется с возвратами из всех
пассивных
вызовов на том же
flag
: это означает, что все параллельные вызовы
std::call_once
гарантированно наблюдают любые побочные эффекты, созданные
активным
вызовом, без дополнительной синхронизации.
Содержание |
Параметры
| flag | - | объект, для которого выполняется ровно одна функция |
| f | - | Callable объект для вызова |
| args... | - | аргументы для передачи в функцию |
Возвращаемое значение
(нет)
Исключения
-
std::system_error
если любое условие препятствует выполнению вызовов
std::call_onceв соответствии со спецификацией. - Любое исключение, выброшенное f .
Примечания
Если параллельные вызовы
std::call_once
передают разные функции
f
, не определено, какая именно
f
будет вызвана. Выбранная функция выполняется в том же потоке, что и вызов
std::call_once
, которому она была передана.
Инициализация
статических переменных внутри функции
гарантированно происходит только один раз даже при вызове из нескольких потоков и может быть более эффективной, чем эквивалентный код с использованием
std::call_once
.
Эквивалентом этой функции в POSIX является
pthread_once
.
Пример
#include <iostream> #include <mutex> #include <thread> std::once_flag flag1, flag2; void simple_do_once() { std::call_once(flag1, [](){ std::cout << "Simple example: called once\n"; }); } void may_throw_function(bool do_throw) { if (do_throw) { std::cout << "Throw: call_once will retry\n"; // это может появиться более одного раза throw std::exception(); } std::cout << "Did not throw, call_once will not attempt again\n"; // гарантированно один раз } void do_once(bool do_throw) { try { std::call_once(flag2, may_throw_function, do_throw); } catch (...) {} } int main() { std::thread st1(simple_do_once); std::thread st2(simple_do_once); std::thread st3(simple_do_once); std::thread st4(simple_do_once); st1.join(); st2.join(); st3.join(); st4.join(); std::thread t1(do_once, true); std::thread t2(do_once, true); std::thread t3(do_once, false); std::thread t4(do_once, true); t1.join(); t2.join(); t3.join(); t4.join(); }
Возможный вывод:
Simple example: called once Throw: call_once will retry Throw: call_once will retry Throw: call_once will retry Did not throw, call_once will not attempt again
Отчеты о дефектах
Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| LWG 2080 | C++11 |
std::invalid_argument
would be thrown if
f
is invalid,
but the scenario where f is invalidated is not specified |
removed this error condition |
| LWG 2442 | C++11 | the arguments were copied and/or moved before invocation | no copying/moving is performed |
Смотрите также
|
(C++11)
|
вспомогательный объект для гарантии того, что
call_once
вызывает функцию только один раз
(класс) |
|
Документация C
для
call_once
|
|