Spec-Zone.ru › C++

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++.

DR Применено к Поведение, как опубликовано Правильное поведение
LWG 2080 C++11 std::invalid_argument было бы брошено, если f недействительно,
но сценарий, в котором f становится недействительным, не указан
удалено это условие ошибки
LWG 2442 C++11 аргументы копировались и/или перемещались до вызова копирование/перемещение не выполняется

См. также

once_flag
(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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API