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_onceflagуказывает, что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"; // this may appear more than once
throw std::exception();
}
std::cout << "Did not throw, call_once will not attempt again\n"; // guaranteed once
}
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 | Применено к | Поведение, как опубликовано | Правильное поведение |
|---|---|---|---|
| LWG 2080 | C++11 |
std::invalid_argument было бы брошено, если f недействительно,но сценарий, в котором f становится недействительным, не указан | удалено это условие ошибки |
| LWG 2442 | C++11 | аргументы копировались и/или перемещались до вызова | копирование/перемещение не выполняется |
См. также
|
(C++11) | вспомогательный объект для обеспечения того, что call_once вызывает функцию только один раз (класс) |
C документация для call_once |
|
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/thread/call_once