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

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

Spec-Zone.ru

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