collaborative_call_once

[algorithms.collaborative_call_once]

関数を 1 度だけ実行する関数テンプレート。


// <oneapi/tbb/collaborative_call_once.h> ヘッダーで定義 

namespace oneapi { 
    namespace tbb { 

        template<typename Func, typename...Args> 
        void collaborative_call_once(collaborative_once_flag& flag, Func&& func, Args&&... args); 

    } // namespace tbb 
} // namespace oneapi

要件:

  • Func タイプは、[function.objects] ISO C++ 標準の関数オブジェクトの要件を満たしている必要があります。

Func オブジェクトは、同時に呼び出されても 1 度だけ実行されます。これにより、同じ collaborative_once_flag でブロックされた他のスレッドが Func オブジェクト内で呼び出される oneTBB 並列構造にジョインできるようになります。

Func オブジェクトから例外がスローされると、Func オブジェクトを呼び出したスレッドが例外を受け取ります。同じ collaborative_once_flag でブロックされたスレッドの 1 つが Func オブジェクトを呼び出します。

collaborative_once_flag クラス

次の例は、cachedProperty フィールドに “遅延初期化” パターンが実装されているクラスを示しています。


#include "oneapi/tbb/collaborative_call_once.h" 
#include "oneapi/tbb/parallel_reduce.h" 
#include "oneapi/tbb/blocked_range.h" 

extern double foo(int i); 

class LazyData { 
    oneapi::tbb::collaborative_once_flag flag; 
    double cachedProperty; 
public: 
    double getProperty() { 
        oneapi::tbb::collaborative_call_once(flag, [&] { 
            // シリアル部分 
            double result{}; 

            // スレッドが連携する並列部分 
            result = oneapi::tbb::parallel_reduce(oneapi::tbb::blocked_range<int>(0, 1000), 0., 
                [] (auto r, double val) { 
                    for(int i = r.begin(); i != r.end(); ++i) { 
                        val += foo(i); 
                    } 
                    return val; 
                }, 
                std::plus<double>{} 
            ); 

            // シリアル部分を継続 
            cachedProperty = result; 
        }); 
        return cachedProperty; 
    } 
};