Namespaces
Variants

std:: call_once

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
Generic lock management
(C++11)
(C++11)
(C++11)
call_once
(C++11)
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
Free functions for atomic operations
Free functions for atomic flags
定義済みヘッダー <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 の呼び出しは passive として知られる)。
  • それ以外の場合、 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 の呼び出しは exceptional (例外的呼び出し)として知られています)。
  • その呼び出しが正常に戻った場合(このような std::call_once の呼び出しは returning (戻り呼び出し)として知られています)、 flag が反転され、同じ flag を持つ他のすべての std::call_once 呼び出しは passive (受動的)であることが保証されます。

同じ flag 上のすべての アクティブ な呼び出しは、ゼロ個以上の 例外送出 呼び出しと、それに続く1つの 正常復帰 呼び出しから成る単一の全順序を形成します。各 アクティブ 呼び出しの終了は、その順序における次の アクティブ 呼び出しと同期します。

returning 呼び出しからの戻りは、同じ flag に対するすべての passive 呼び出しからの戻りと同期します(synchronizes-with):これは、 std::call_once へのすべての同時呼び出しが、 active 呼び出しによって行われた副作用を、追加の同期なしで確実に観察することを保証します。

目次

パラメータ

flag - 正確に関数が1つだけ実行されるオブジェクト
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"; // 1回のみ保証
}
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ドキュメント for call_once