ソケットが1つs
あり、現在利用可能なデータがなく、それがブロッキングソケットであり、recv
一度に2つのスレッドから呼び出すとどうなりますか?スレッドの1つがデータを取得しますか?両方ともそれを取得しますか?2回目の呼び出しrecv
でエラーが発生しますか?
4 に答える
1 つのスレッドがそれを取得し、どのスレッドかを知る方法はありません。
これは合理的な設計とは思えません。recv()
同じソケットで2 つのスレッドを呼び出す必要がある理由はありますか?
ソケットの実装はスレッドセーフである必要があるため、データが利用可能になったときに1つのスレッドだけがデータを取得する必要があります。他の呼び出しはブロックする必要があります。
これについての参照は見つかりませんが、私の理解は次のとおりです。
ベンダーによるスレッドセーフの保証は、複数のスレッドがそれぞれ独自のソケットを安全に使用できることを意味するだけかもしれません。単一の呼び出しで原子性が保証されるわけではなく、複数のスレッド間でのソケットのデータの特定の割り当てが保証されるわけでもありません。
スレッド A が、TCP データ ストリーミングを高速で受信しているソケットで recv() を呼び出すとします。recv() をアトミック呼び出しにする必要がある場合、スレッド A は他のすべてのスレッドの実行をブロックする可能性があります。これは、すべてのデータを取得するために継続的に実行する必要があるためです (とにかく、そのバッファーがいっぱいになるまで)。良い。したがって、 recv() がコンテキスト切り替えの影響を受けないとは思いません。
逆に、スレッド A がTCP ソケットで recv() へのブロッキング呼び出しを行い、データがゆっくり入ってくるとします。したがって、recv() への呼び出しは、errno を EAGAIN に設定して戻ります。
これらのいずれの場合でも、スレッド A がまだデータを受信しているときに、スレッド B が同じソケットで recv() を呼び出すとします。スレッド A がデータの受け取りを停止し、スレッド B がデータの受信を開始できるようになるのはいつですか? スレッド A がソケットでの操作の最中だったことを記憶しようとする Unix 実装を私は知りません。代わりに、その使用をネゴシエートするのはアプリケーション (スレッド A および B) 次第です。
一般に、スレッドの 1 つだけが 1 つのソケットで recv() を呼び出すようにアプリを設計することをお勧めします。
recvのマニュアルページから
SOCK_STREAM ソケットの recv() は、提供されたバッファのサイズが保持できる限り多くの利用可能な情報を返します。
質問で指定されていないため、TCPを使用していると仮定しましょう。スレッド A とスレッド B の両方がソケット s の recv() をブロックしているとします。s に受信するデータがあると、スレッドの 1 つ (A としましょう) のブロックを解除し、データを返します。返されるデータは、私たちに関する限り、ランダムなサイズになります。スレッド A は、受信したデータを検査し、完全な「メッセージ」があるかどうかを判断します。ここで、メッセージはアプリケーション レベルの概念です。
スレッド A は、完全なメッセージがないと判断したため、recv() を再度呼び出します。しかし、その間、B はすでに同じソケットでブロックしており、スレッド A 向けの残りの「メッセージ」を受信しています。
スレッド A とスレッド B の両方に不完全なメッセージがあり、コードの記述方法によっては、データが無効として破棄されるか、奇妙で微妙なエラーが発生します。
これは経験上知らなかったと言いたいです。
そのため、recv() 自体は技術的にはスレッド セーフですが、TCP で使用している場合に 2 つのスレッドで同時に呼び出すことはお勧めできません。
私の知る限り、UDP を使用しているときは完全に安全です。
これが役立つことを願っています。