条件変数またはタスクによるスレッド同期

promise と future を使用してスレッドを同期する場合、条件変数と多くの共通点があります。しかし、ほとんどの場合、タスクの方が適しています。

スレッドの同期

全体像を把握するには、事実を把握します。この表は、条件変数とタスク (promise および future) を比較しています。

promise と future に対する条件変数の利点は、条件変数を使用してスレッドを複数回同期できることです。それとは対照的に、promise はその通知を 1 回しか送信できません。したがって、条件変数の機能を得るには、promise と future のペアをさらに使用する必要があります。ただし、条件変数を 1 つの同期にのみ使用する場合、条件変数を正しく使用するのははるかに難しくなります。したがって、promise と future のペアは共有変数を必要としないため、ロックも必要ありません。誤ったウェイクアップや失われたウェイクアップが発生する傾向はありません。それに加えて、例外を処理できます。 したがって、条件変数よりもタスクを好む理由はたくさんあります。

タスクを使用してスレッドを同期するにはどうすればよいですか?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// promiseFutureSynchronize.cpp

#include <future>
#include <iostream>
#include <utility>


void doTheWork(){
 std::cout << "Processing shared data." << std::endl;
}

void waitingForWork(std::future<void>&& fut){

 std::cout << "Worker: Waiting for work." << std::endl;
 fut.wait();
 doTheWork();
 std::cout << "Work done." << std::endl;

}

void setDataReady(std::promise<void>&& prom){

 std::cout << "Sender: Data is ready." << std::endl;
 prom.set_value();

}

int main(){

 std::cout << std::endl;

 std::promise<void> sendReady;
 auto fut= sendReady.get_future();

 std::thread t1(waitingForWork,std::move(fut));
 std::thread t2(setDataReady,std::move(sendReady));

 t1.join();
 t2.join();

 std::cout << std::endl;
 
}

とても簡単です。

プロミス sendReady (32 行目) の助けを借りて、未来の未来 (34 行目) を取得します。 promise は、この場合、彼の戻り値 void (std::promise sendReady) によって、通知の送信のみが可能であることを通知します。両方の通信エンドポイントがそれぞれスレッド t1 に移動されます (行 35 および 36)。 future は fut.wait() の呼び出し (15 行目) で promise の通知を待機しています:prom.set_value() (24 行目)。

同様に、プログラムの出力としての構造は、条件変数に関するデン ポストのプログラムと一致します。

次は?

以上がマルチスレッド インターフェースの概要でした。では、C++ でのマルチスレッドについて詳しく見ていきましょう。ほとんどのプログラマーは C++ メモリ モデルの機能を使用することはありませんが、使用すべきではありませんが、マルチスレッド プログラミングの課題についてより深い洞察が得られます。次の投稿は、C++ メモリ モデルの概要から始まります。 (校正者 Alexey Elymanov )