D-programming-concurrency

提供:Dev Guides
移動先:案内検索

Dプログラミング-並行性

並行性とは、プログラムを一度に複数のスレッドで実行することです。 並行プログラムの例は、多数のクライアントに同時に応答するWebサーバーです。 並行性はメッセージの受け渡しでは簡単ですが、データ共有に基づいている場合は非常に記述が困難です。

スレッド間で渡されるデータはメッセージと呼ばれます。 メッセージは、任意のタイプと任意の数の変数で構成できます。 すべてのスレッドにはIDがあり、メッセージの受信者を指定するために使用されます。 別のスレッドを開始するスレッドは、新しいスレッドの所有者と呼ばれます。

Dでのスレッドの開始

関数spawn()は、パラメーターとしてポインターを取り、その関数から新しいスレッドを開始します。 呼び出される可能性のある他の関数を含む、その関数によって実行される操作はすべて、新しいスレッドで実行されます。 所有者とワーカーの両方が、独立したプログラムであるかのように別々に実行を開始します。

import std.stdio;
import std.stdio;
import std.concurrency;
import core.thread;

void worker(int a) {
   foreach (i; 0 .. 4) {
      Thread.sleep(1);
      writeln("Worker Thread ",a + i);
   }
}

void main() {
   foreach (i; 1 .. 4) {
      Thread.sleep(2);
      writeln("Main Thread ",i);
      spawn(≈worker, i *5);
   }

   writeln("main is done.");
}

上記のコードがコンパイルおよび実行されると、前のセクションで作成されたファイルを読み取り、次の結果を生成します-

Main Thread 1
Worker Thread 5
Main Thread 2
Worker Thread 6
Worker Thread 10
Main Thread 3
main is done.
Worker Thread 7
Worker Thread 11
Worker Thread 15
Worker Thread 8
Worker Thread 12
Worker Thread 16
Worker Thread 13
Worker Thread 17
Worker Thread 18

Dのスレッド識別子

モジュールレベルでグローバルに使用できる_thisTid_変数は、常に現在のスレッドのIDです。 また、spawnが呼び出されたときにthreadIdを受け取ることができます。 例を以下に示します。

import std.stdio;
import std.concurrency;

void printTid(string tag) {
   writefln("%s: %s, address: %s", tag, thisTid, &thisTid);
}

void worker() {
   printTid("Worker");
}

void main() {
   Tid myWorker = spawn(&worker);

   printTid("Owner ");

   writeln(myWorker);
}

上記のコードがコンパイルおよび実行されると、前のセクションで作成されたファイルを読み取り、次の結果を生成します-

Owner : Tid(std.concurrency.MessageBox), address: 10C71A59C
Worker: Tid(std.concurrency.MessageBox), address: 10C71A59C
Tid(std.concurrency.MessageBox)

Dでメッセージを渡す

関数send()はメッセージを送信し、関数receiveOnly()は特定のタイプのメッセージを待ちます。 prioritySend()、receive()、およびreceiveTimeout()という名前の他の関数があり、これらについては後で説明します。

次のプログラムの所有者は、ワーカーにint型のメッセージを送信し、double型のワーカーからのメッセージを待ちます。 所有者が負のintを送信するまで、スレッドはメッセージを繰り返し送信します。 例を以下に示します。

import std.stdio;
import std.concurrency;
import core.thread;
import std.conv;

void workerFunc(Tid tid) {
   int value = 0;
   while (value >= 0) {
      value = receiveOnly!int();
      auto result = to!double(value)* 5; tid.send(result);
   }
}

void main() {
   Tid worker = spawn(&workerFunc,thisTid);

   foreach (value; 5 .. 10) {
      worker.send(value);
      auto result = receiveOnly!double();
      writefln("sent: %s, received: %s", value, result);
   }

   worker.send(-1);
}

上記のコードがコンパイルおよび実行されると、前のセクションで作成されたファイルを読み取り、次の結果を生成します-

sent: 5, received: 25
sent: 6, received: 30
sent: 7, received: 35
sent: 8, received: 40
sent: 9, received: 45

Dで待機するメッセージの受け渡し

待機でメッセージを渡す簡単な例を以下に示します。

import std.stdio;
import std.concurrency;
import core.thread;
import std.conv;

void workerFunc(Tid tid) {
   Thread.sleep(dur!("msecs")( 500 ),);
   tid.send("hello");
}

void main() {
   spawn(&workerFunc,thisTid);
   writeln("Waiting for a message");
   bool received = false;

   while (!received) {
      received = receiveTimeout(dur!("msecs")( 100 ), (string message) {
         writeln("received: ", message);
      });

      if (!received) {
         writeln("... no message yet");
      }
   }
}

上記のコードがコンパイルおよび実行されると、前のセクションで作成されたファイルを読み取り、次の結果を生成します-

Waiting for a message
... no message yet
... no message yet
... no message yet
... no message yet
received: hello