スレッドとやり取りをして自分で同期をするかわりに、Dは複数コアを活用する優れた手段として メッセージパッシングが使えます。スレッドは仕事を分配しそれら自身を同期させるために、 任意の値であるメッセージを使って連絡を取り合います。スレッドたちはマルチスレッディングの よくある問題を避けるために設計によってデータを共有しません。
Dでメッセージパッシングを実装するすべての関数はstd.concurrency
モジュールにあります。
spawn
はユーザ定義関数をもとにした新しいスレッドを作ります:
auto threadId = spawn(&foo, thisTid);
thisTid
はstd.concurrency
組み込みでメッセージパッシングに必要な
現在のスレッドを参照するものです。spawn
は最初の引数としての関数と、
その関数に向けた追加の引数を引数にとります。
void foo(Tid parentTid) {
receive(
(int i) { writeln("An ", i, " was sent!"); }
);
send(parentTid, "Done");
}
receive
関数はswitch
-case
のように、他のスレッドから受け取った
値を、受け取った値の型により、渡されたdelegates
に送ります。
特定のスレッドにメッセージを送るのには関数send
とそのスレッドのidを使います:
send(threadId, 42);
receiveOnly
を特定の型のみを受け取るのに使えます:
string text = receiveOnly!string();
assert(text == "Done");
receive
ファミリー関数は何かがスレッドのメールボックスに送られてくるまでブロックします。
xxxxxxxxxx
import std.stdio : writeln;
import std.concurrency : receive, receiveOnly,
send, spawn, thisTid, Tid;
/*
小さなスレッド軍隊用のメッセージとして使われる
カスタム構造体です。
*/
struct NumberMessage {
int number;
this(int i) {
this.number = i;
}
}
/*
他のスレッドのストップサインとして使われるメッセージです
*/
struct CancelMessage {
}
/// CancelMessageに応答します
struct CancelAckMessage {
}
/*
引数として渡された親idを得る
スレッドワーカーメイン関数。
*/
void worker(Tid parentId)
{
bool canceled = false;
writeln("Starting ", thisTid, "...");
while (!canceled) {
receive(
(NumberMessage m) {
writeln("Received int: ", m.number);
},
(string text) {
writeln("Received string: ", text);
},
(CancelMessage m) {
writeln("Stopping ", thisTid, "...");
send(parentId, CancelAckMessage());
canceled = true;
}
);
}
}
void main()
{
Tid[] threads;
// 小さな10個のワーカースレッドを生成。
for (size_t i = 0; i < 10; ++i) {
threads ~= spawn(&worker, thisTid);
}
// 奇数のスレッドは数値を、偶数のスレッドは文字列を取得します!
foreach(idx, ref tid; threads) {
import std.string : format;
import std.conv : to;
if (idx % 2) {
int num = idx.to!int;
send(tid, NumberMessage(num));
} else {
send(tid, format("T=%d", idx));
}
}
// そしてすべてのスレッドはキャンセルメッセージを受け取ります!
foreach(ref tid; threads) {
send(tid, CancelMessage());
}
// そしてすべてのスレッドが停止リクエストに応答するのを待ちます
foreach(ref tid; threads) {
receiveOnly!CancelAckMessage;
writeln("Received CancelAckMessage!");
}
}