ZeroMq ガイドを読んだところ、次のことがわかりました。
スレッド間で ØMQ ソケットを共有してはなりません。ØMQ ソケットはスレッドセーフではありません。技術的には可能ですが、セマフォ、ロック、またはミューテックスが必要です。これにより、アプリケーションが遅くなり、壊れやすくなります。スレッド間でソケットを共有することがリモートで妥当な唯一の場所は、ソケットでガベージ コレクションのような魔法を行う必要がある言語バインディングです。
そして後で:
注意:ソケットを作成したスレッド以外では、ソケットを使用したり閉じたりしないでください。
また、ZeroMQContext
がスレッドセーフであることも理解しました。
クラスが別のクラスのイベントに登録する場合、.Net では、このイベントは、リスナーが作成されたスレッドとは異なるスレッドから呼び出される可能性があります。
イベントハンドラー内からZeroMQ-Socketsを介して何かをディスパッチできるオプションは2つしかないと思います。
- eventhandler-invoking-thread を、ZeroMQ-
Socket
が作成されたスレッドに同期します。 - スレッドセーフな ZeroMQ- を使用して、新しい ZeroMQ- を作成する
Socket
/イベントSocket
ハンドラ内のスレッドの既存の ZeroMQ- を取得するContext
0MQ-Guide が最初のものを思いとどまらせているようで、スレッドごとに新しい ZeroMq-Socket を作成することはパフォーマンス/方法ではないと思います。
私の質問:
イベントハンドラー内から 0MQ を介してメッセージを発行するための正しいパターン (意図されている方法) は何ですか?
また、ガイドの作成者は、次のように書いたときに、.Net の ZeroMQ-Binding を念頭に置いていましたか?
スレッド間でソケットを共有することがリモートで妥当な唯一の場所は、ソケットでガベージ コレクションのような魔法を行う必要がある言語バインディングです。?
私の問題/質問を強調するためのサンプルコードを次に示します。
public class ExampleClass
{
public event EventHandler<ByteEventArgs> SomethinIsCalledFromAnotherThread;
}
public class ByteEventArgs : EventArgs
{
public byte[] BytesToSend;
}
public class Dispatcher
{
ZMQ.Context ctx;
public Dispatcher(ZMQ.Context mqcontext, ExampleClass exampleClassInstance)
{
this.ctx = mqcontext;
exampleClassInstance.SomethinIsCalledFromAnotherThread += new EventHandler<ByteEventArgs>(exampleClass_SomethinIsCalledFromAnotherThread);
}
void exampleClass_SomethinIsCalledFromAnotherThread(object sender, ByteEventArgs e)
{
// this method might be called by a different thread. So I have to get a new socket etc?
using (var socket = ctx.Socket(ZMQ.SocketType.PUSH))
{
// init socket etc..... and finally:
socket.Send(e.BytesToSend);
}
// isn't that too much overhead?
}
}