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"; // 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++.
| Отчёт об ошибке | Применяется к | Поведение согласно опубликованной версии | Исправленное поведение |
|---|---|---|---|
| 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/cpp/thread/call_once