Review for N4399: “Working Draft, Technical Specification for C++ Extensions for Concurrency” 稲葉 一浩 ([email protected]) SC22/C++WG May 2015 参考資料 • レポジトリ – https://github.com/cplusplus/concurrency_ts • 関連 Proposal – – – – ... N3784 : “Improvements to std::future<T> and Related APIs” ... N3785 : “Executors and Schedulers” ... N4392 : “C++ Latches and Barriers” ... N4162 : “Atomic Smart Pointers” • TS Draft – – – – – – N3970 : May 2014 (≒N3784 + N3785) Editor note: N3971, Comments: N4032, N4048 N4107 : Jul 2014 (-= N3785) Editor note: N4108, Revisions: N4123, N4313 N4399 : Apr 2015 (+= N4204, N4162) Editor Note: N4400 N4399 の内容 • 3本立て 1. Improvements to std::future<T> and Related APIs 2. Latches and Barriers 3. Atomic Smart Pointers おさらい: futureとは • 「どこかで実行された計算の結果がそのうち 入る」行き先を表す std::future<int> ft = std::async([](){ // 非同期にこの関数を実行 return 42; }); if (ft.wait_for(std::chrono::seconds(1)) == std::future_status::ready) { int v = ft.get(); // 42 } 1. Improvements to std::future<T> • 以下のメンバ関数を追加 – future(future<future<R>>&& rhs); – see below then(F&& func); – bool is_ready() const noexcept; • 以下の関数を追加 – – – – – – see below when_all(InputIterator begin, InputIterator end); see below when_all(Futures&&... futures); see below when_any(InputIterator begin, InputIterator end); see below when_any(Futures&&... futures); future<decay_t<T>> make_ready_future(T&& value); future<T> make_execeptional_future(exception_ptr ex); 複数のfuture(やfutureを作る計算)を組み合わせて 新しいfutureを作るユーティリティ関数群 1. Improvements to std::future<T> • 以下のメンバ関数を追加 – future(future<future<R>>&& rhs); – see below then(F&& func); – bool is_ready() const noexcept; • 以下の関数を追加 – – – – – – C++11 ドラフト段階では一度 提案されていた関数。復活 see below when_all(InputIterator begin, InputIterator end); see below when_all(Futures&&... futures); see below when_any(InputIterator begin, InputIterator end); see below when_any(Futures&&... futures); future<decay_t<T>> make_ready_future(T&& value); future<T> make_execeptional_future(exception_ptr ex); 1. Improvements to std::future<T> • 以下のメンバ関数を追加 – future(future<future<R>>&& rhs); – see below then(F&& func); – bool is_ready() const noexcept; • 以下の関数を追加 – – – – – – see below when_all(InputIterator begin, InputIterator end); see below when_all(Futures&&... futures); see below when_any(InputIterator begin, InputIterator end); see below when_any(Futures&&... futures); future<decay_t<T>> make_ready_future(T&& value); future<T> make_execeptional_future(exception_ptr ex); 1. Improvements to std::future<T> • future<T> ft = ...; ft.then(func); • 「ft の値が取り出し可能になったら func(ft) を実行してその値を 返す future」 を即座に返す • func は future<T> を引数にとる。 – T ではない。 – Haskell の Monad (引数型はT) や ECMAScript6 の Promise (引数型はT、 Exception時のためにもう一つ関数オブジェクトを渡す) とは型が違う • funcの返値型が future<R> なら then の型も future<R> • funcの返値型がそれ以外の R なら then の型は future<R> – (前者が “implicit unwrapping” と呼ばれる特殊規則。 future<future<R>> にはならない) 1. Improvements to std::future<T> • future<T> ft = make_ready_future(v); • 「値 v が既に取り出し可能な状態になっている future」 – T を future<T> に変換する • future(future<future<R>>&& rhs); – future<future<T>> を future<T> に変換する • rhsとrhs.get()がreadyならready。get()はrhs.get()の結果 になる 1. Improvements to std::future<T> • 以下のメンバ関数を追加 – future(future<future<R>>&& rhs); – see below then(F&& func); – bool is_ready() const noexcept; • 以下の関数を追加 – – – – – – see below when_all(InputIterator begin, InputIterator end); see below when_all(Futures&&... futures); see below when_any(InputIterator begin, InputIterator end); see below when_any(Futures&&... futures); future<decay_t<T>> make_ready_future(T&& value); future<T> make_execeptional_future(exception_ptr ex); 1. Improvements to std::future<T> • future<vector< typename iterator_traits<InputIterator>::value_type >> when_all(InputIterator, InputIterator); • future<tuple<decay_t<Futures>...>> when_all(Futures&&...); – 「引数に渡した全てのfutureがreadyになったら readyになるfuture」を返す。返値はfutureの vector/tupleのfuture。 • readyになったら引数のfutureがmoveされる 1. Improvements to std::future<T> • template<class Sequence> struct when_any_result { size_t index; Sequence futures; }; • future<when_any_result<vector<typename iterator_traits<InputIterator>::value_type>>> when_any(InputIterator, InputIterator); • future<when_any_result<tuple<decay_t<Futures>...>>> when_any(Futures&&... futures); – 引数どれか一つ以上がreadyになったらreadyになるfutureを返 す • 引数が0個なら即座にreadyとなる – 返値は「引数全部のSequenceと発火したindex」という意図だと 思われるが、現在のdraftではindexについて何も触れられてい ない (ミス?) 気になったところ • then や when_all や when_any に引数として 渡したfutureは、関数から返った時点で無効 になっている – “Postcondition” の項を見るとわかる – “Effects” の項を見ると、新しく作った future が ready になった後に move が行われることは書か れているが、関数呼び出し時については言及さ れていない 2. Latches and Barriers • スレッド間同期プリミティブ – カウンタの初期値 n • 最初に同期ポイントに入った n 個のスレッドが “participating thread ” となる – 各スレッドは基本的に 「1 減らして待つ」 ことができる – カウンタが 0 になったら待ちスレッド全て実行再開 • latch – Single-use (一度カウンタが 0 になったら destruct しかできない) • barrier – Single-use ではない (カウンタが0になったあと戻る) – arrive_and_drop() という操作で participating thread から抜けられる • flex_barrier – コンストラクタに関数オブジェクト (ptrdiff_t ()) を指定できる。 – カウンタ 0 になった時に呼ばれる。 – -1 を返すと barrier と同じ動作。それ以外の値を返すと新しい participating thread 集合のサイズとして扱われる class latch { public: explicit latch(ptrdiff_t count); void void bool void count_down_and_wait(); count_down(ptrdiff_t n); is_ready() const noexcept; wait() const; }; 少し前までの proposal では arrive_and_wait() だった。 count_down(n) に合わせて改名? class barrier { public: explicit barrier(ptrdiff_t num_threads); void arrive_and_wait(); void arrive_and_drop(); }; class flex_barrier { public: template <class F> flex_barrier(ptrdiff_t num_threads, F completion); explicit flex_barrier(ptrdiff_t num_threads); void arrive_and_wait(); void arrive_and_drop(); }; 3. Atomic Smart Pointers • atomic_shared_ptr<T> • atomic_weak_ptr<T> – shared_ptr<T> と weak_ptr<T> の atomic版 • “The behavior of all operations is as specified in C++14 §29.6.5, unless stated otherwise.” • “When any operation on an atomic_shared_ptr or atomic_weak_ptr causes an object to be destroyed or memory to be deallocated, that destruction or deallocation shall be sequenced after the changes to the atomic object's state.” – atomic_unique_ptr<T> は無い(なぜ?)
© Copyright 2025 ExpyDoc