通信プログラムを送信スレッドと受信スレッドに別けては駄目

TCP/IPやシリアル通信において、データの受信と送信を別々のスレッドでおこなえば、アプリケーションを単純化し、パフォーマンスも向上するように感じるかもしれない。これは初級から中級のプログラマがやりがちなことだが、多くの場合は徒労に終わる。

一つ目の問題として、実はOSは送信と受信を同時に実行することが出来ない。アプリケーションからドライバに対する要求はFIFOキューに格納される。デバイスドライバはFIFOキューに格納された命令を順番に処理していく。してがってAスレッドの受信命令と、Bスレッドの送信命令がキューに格納されている場合、Aスレッドの受信命令の処理が終わらない限り、Bスレッドの送信命令も待機することになる。アプリケーション側のスレッドを単純に分けただけでは、送信と受信を非同期におこなう事は出来ない。

送信と受信をほぼ同時に処理するにはノンブロッキングモードを使う必要がある。ノンブロッキングモードなら、ドライバはデータの有無に拘わらず直ちに応答を返して次の処理に進むので、受信と送信をほぼ同時に実行することが出来る。

二つ目の問題として、殆どのプロトコルにおいて、送信が正常に行われたか判断するためには受信データが必要になることにある。送信処理と受信処理は互いに深く関係した密結合となる。そのため送信処理と受信処理との間で情報を交換するためにフラグや排他制御が必要になる。正常処理だけなら良いか、これに異常時のリカバリ処理まで含むと状態遷移が複雑になり、余程慎重に設計しないとスパゲティのように絡み合ったソースコードになってしまうはずだ。

通信プロトコルが送信とその応答を非同期的に処理することを前提に設計されていたり、あるいは非同期的に処理することでパフォーマンスの向上を臨んでいるなら、送信と受信を分離する価値はあるだろう。そうでないなら、止めた方が無難だ。

ではどのような設計なら良いのだろうか。私見だが「他スレッドからFifo Queue等で要求を受付け、コマンドの送信、応答の受信、必要に応じてエラーリカバリ処理を行って、要求元スレッドに応答を返すようなスレッド」を作るのが良いと思う。この方法だと通信に伴って発生する状態遷移を単一スレッドの中に閉じ込めることが出来るので、複雑さが増す事を避けて実装する事が出来る。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です