着信トラフィックの TCP ソケットをリッスンし、受信したデータをメイン スレッドがアクセスできるようにバッファリングするワーカー スレッドがあります (このソケットをAと呼びましょう)。ただし、ワーカー スレッドは、データが入ってこない場合でも、いくつかの定期的な操作 (たとえば、1 秒に 1 回)select()
を実行する必要があります。(ノンブロッキング ソケットで呼び出しreceive()
てから 1 秒間スリープするのは良くないことに注意してください。メイン スレッドが常にすぐに処理できるとは限らない場合でも、着信データはメイン スレッドですぐに利用できるようにする必要があります。バッファリングが必要です。)
ここで、ワーカー スレッドに他の処理をすぐに実行するよう通知できる必要もあります。select()
メイン スレッドから、すぐにワーカー スレッドを返す必要があります。今のところ、私はこれを次のように解決しました(基本的にこことここから採用されたアプローチ):
プログラムの起動時に、ワーカー スレッドはこの目的のためにデータグラム (UDP) タイプの追加のソケットを作成し、それを任意のポートにバインドします (このソケットをBと呼びましょう)。同様に、メイン スレッドは送信用のデータグラム ソケットを作成します。への呼び出しselect()
で、ワーカー スレッドはAとBの両方を にリストしますfd_set
。メインスレッドがシグナルを送る必要があるとき、それsendto()
は の対応するポートへの数バイトlocalhost
です。ワーカー スレッドに戻り、 Bfd_set
がafterselect()
リターンに残っている場合は、recvfrom()
が呼び出され、受信したバイトは単純に無視されます。
これは非常にうまく機能しているようですが、主にBに追加のポートをバインドする必要があるため、また、失敗する可能性のあるソケット API 呼び出しがいくつか追加されるため、このソリューションが気に入っているとは言えません。ケースごとに適切なアクションを見つけたいと本当に思っています。
理想的には、 Aselect()
を入力として取り、すぐに返す以外は何もしない関数を呼び出したいと思います。しかし、私はそのような機能を知りません。(たとえば、ソケットは可能だと思いshutdown()
ますが、副作用は実際には受け入れられません:)
これが不可能な場合、次善の策はBを作成することです。これは、実際の UDP ソケットよりもはるかにダミーであり、限られたリソース (合理的な量のメモリを超えて) を実際に割り当てる必要はありません。Unix ドメインソケットはまさにこれを行うと思いますが、解決策は、現在私が持っているものよりもはるかにクロスプラットフォームである必要はありませんが、適度な量の#ifdef
ものは問題ありません. (私は主に Windows と Linux をターゲットにしています - ちなみに C++ を書いています。)
2 つの別個のスレッドを取り除くためにリファクタリングを提案しないでください。この設計が必要なのは、メイン スレッドが長期間にわたってブロックされる可能性があり (たとえば、集中的な計算を実行していて、receive()
計算の最も内側のループから定期的に呼び出しを開始できない場合など)、その間、誰かが着信データをバッファリングする必要があるためです。 (そして、私が制御できない理由により、送信者になることはできません)。
これを書いている今、誰かが必ず「Boost.Asio」と答えるだろうと思ったので、初めて見ました... 明らかな解決策を見つけることができませんでした。ソケットA の作成方法にも (簡単に) 影響を与えることはできませんが、必要に応じて他のオブジェクトにラップさせることができるはずです。