1: 2010-10-22 (金) 22:41:21 SHOO ソース
With "vote" plugin. at 2012-06-09 (土) 23:24:16
Line 1: Line 1:
 +TITLE:Exchanging Messages between Threads
 +#navi
 +* 元記事について [#h6fc3fbd]
 +本記事は [http://amzn.to/9gr2A3 TDPL] のなかの第13章 Concurrency を、著者であるAndrei Alexandrescu様の許可のもと翻訳・公開しております。 翻訳を快諾してくださったAndrei Alexandrescu様に感謝致します。~
 +参考: [http://amzn.to/9gr2A3 TDPL] P''401''~''403''~
 +参考: [http://www.informit.com/articles/article.aspx?p=1609144&seqNum=5 Concurrency in the D programming Language](この章は同書のサンプルとして原文も公開されています)
 +
 +* 訳文 [#f0dd0b1a]
 +
 +** 13.5 スレッド間のメッセージ交換 [#ic8bcef5]
 +
 + 好き勝手に交錯してメッセージを印字するスレッドはあまり面白くないものです。スレッドが協力して確実に以下のようにメッセージを印字するよう、先の例を修正してみましょう。
 +
 + Main thread: 0
 + Secondary thread: 0
 + Main thread: 1
 + Secondary thread: 1
 + ...
 + Main thread: 99
 + Secondary thread: 99
 +
 + これを達成するには、2つのスレッドの間にちょっとしたプロトコルを定義する必要があります。メインスレッドは「この数を印字せよ」というメッセージをセカンダリスレッドへ送り、セカンダリスレッドは「印字完了」と応答しなければなりません。あまり並行処理らしい例という感じではありませんが、純粋な通信を説明する目的には十分です。現実のアプリケーションでは、スレッドは意味のある作業を行うのにその時間のほとんどを費やし、他のそれぞれとの通信には比較的少ない時間しか割きません。
 +
 + まず、2つのスレッドが通信するためには、お互いの宛先を知る必要があります。プログラムによってはひっきりなしにおしゃべりする沢山のスレッドを持つ場合もあり、よって識別の手立ては不可欠です。スレッドに話しかけるには、その'''''スレッドのid'''''(以降tidと呼びます)を把握せねばならず、これはspawnによって返されます(tidの型名は実際にTidです)。同様に、セカンダリスレッドもまた応答を送信するのにtidを必要とします。これは普通の手紙の封筒に差出人の住所を書くのと同じように、送り手が自身のTidを指定することで簡単に実現できます。コードはこのようになります。
 +
 +#code(d){{{
 +import std.concurrency, std.stdio;
 +void main() {
 +   auto low = 0, high = 100;
 +   auto tid = spawn(&writer);
 +   foreach (i; low .. high) {
 +       writeln("Main thread: ", i);
 +       tid.send(thisTid, i);
 +       enforce(receiveOnly!Tid() == tid);
 +   }
 +}
 +
 +void writer() {
 +   for (;;) {
 +       auto msg = receiveOnly!(Tid, int)();
 +       writeln("Secondary thread: ", msg[1]);
 +       msg[0].send(thisTid);
 +   }
 +}
 +}}}
 +
 + 今度のwriterはメッセージとして必要な情報を受け取るため、引数を取りません。メインスレッドはspawnによって返されるTidを保存し、sendメソッドの呼び出しに使います。この呼び出しは他のスレッドへ2つのデータ、大域プロパティthisTidから得られる現在のスレッドのTidと、印字する整数とを送ります。他のスレッドへ壁越しにデータを投げた後、メインスレッドはreceiveOnlyの呼び出しという形でその応答を待ちます。send関数とreceiveOnly関数は協調して働きます。あるスレッドにおけるsendの呼び出しは、他のスレッドにおけるreceiveOnlyの呼び出しと対応します。receiveOnlyの「only」は、receiveOnlyが特定の型だけを受け付けることから名付けられたものですーたとえば、receiveOnly!bool()の呼び出しにおいては、呼び出し側はboolの値から成るメッセージのみを受け付けます。もし他のスレッドがそれ以外を送った場合、receiveOnlyはMessageMismatch例外を投げます。
 +
 + foreachループを物色するmainのことは放っておいて、このミニプロトコルの別の面を実装するwriterに焦点をあてましょう。writerが時を過ごすループボディは、必ずTidとintから成るメッセージを受け取るところから始まります。receiveOnly!(Tid, int)()の呼び出しはまさにそれを保証します。繰り返しになりますが、メインスレッドが異なる数や型の引き数のメッセージを送った場合、receiveOnlyは例外を投げて失敗します。先に述べた通り、writer内でのreceiveOnlyの呼び出しはmainからのtid.send(thisTid, i)の呼び出しと完全に呼応します。
 +
 + msgの型はTuple!(Tid, int)です。一般的に、複数の引数のメッセージはTupleオブジェクトへ引数毎に1つのメンバという形でまとめられます。しかしもし、メッセージが1つの値のみから成る場合、冗長なTupleへのまとめは起こりません。たとえば、receiveOnly!int()はTuple!intではなくintを返します。
 +
 + writerについて続けると、その次の行は実際の印字を担当しています。タプルmsgについては、msg[0]で最初のメンバ(つまりTid)へアクセスし、msg[1]で2番目のメンバ(int)へアクセスすることを思い出してください。最終的に、writerはコンソールへの書き込みが終わったことを、単に自身のTidを送信側へ送り返すことで知らせますー送り元の住所を確認するだけの空白の手紙のように。「うん、あんたからのメッセージは受け取ったよ、」空白の手紙は暗示します、「それでその通りにやった。今度はあんたの番。」と。メインスレッドは作業を続ける前にこの確認を待ち、そしてループが続いていきます。
 +
 + セカンダリスレッドのTidを送り返すのはこのケースでは余計なことです。intやboolのようなダミーの値を使っても問題ありません。しかし一般的なケースでは互いにメッセージを送る沢山のスレッドがあり、自己識別は重要となります。
 +
 +#navi
 +* 投票とコメント [#c2640116]
 +
 +#vote(#lastvote:e8c00b4b39e7f251aa44f470bc960e3f,大変参考になった[1],参考になった[1],あまり参考にならなかった,まったく参考にならなかった,#notimestamp)
 +#pcomment


トップ   差分 バックアップ 複製 名前変更 リロード印刷に適した表示   ページ新規作成 全ページ一覧 単語検索 最新ページの一覧   ヘルプ   最新ページのRSS 1.0 最新ページのRSS 2.0 最新ページのRSS Atom Powered by xpWiki
Counter: 726, today: 1, yesterday: 1
メインメニュー

ログイン

ユーザー名:


パスワード:





パスワード紛失  |新規登録

Menu