web-dev-qa-db-ja.com

単一のソケットまたはパイプでpoll()またはselect()を実行する複数のスレッド

複数のスレッドが単一のソケットまたはパイプハンドルで同時にpoll()またはselect()呼び出しを実行している状況について、POSIXおよびその他の標準は何と言っていますか?

データが到着した場合、待機中のスレッドの1つだけがウェイクアップされますか、それともすべての待機中のスレッドがウェイクアップされますか?

23
wilx

興味深い質問...現在の [〜#〜] posix [〜#〜] を読みましたが、特定の回答が見つかりませんでした。つまり、同時呼び出しに関する仕様がありません。それで、なぜ標準がすべてが目覚めることを意味すると思うのかを説明します。

text for select/pselectの関連部分は次のとおりです。

正常に完了すると、pselect()またはselect()関数は、readfds、writefds、およびerrorfds引数が指すオブジェクトを変更して、それぞれ読み取り可能、書き込み可能、​​または保留中のエラー条件を示すファイル記述子を示します。 、[...]

以降

O_NONBLOCKクリアを使用した入力関数の呼び出しがブロックされない場合、関数がデータを正常に転送するかどうかに関係なく、記述子は読み取りの準備ができていると見なされます。 (この関数は、データ、ファイルの終わりの表示、またはブロックされていることを示す以外のエラーを返す場合があり、これらの場合のそれぞれで、記述子は読み取りの準備ができていると見なされます。)

要するに(読書の場合のみ)、これは次のように理解できます。

selectはこれをブロックしません。つまり、O_NONBLOCKを使用して入力関数をnext呼び出しても、errno==EWOULDBLOCKでエラーは返されません。 [「次」は上記の私の解釈であることに注意してください。]

この解釈を認める場合、2つの同時select呼び出しは、両方とも読み取り可能として同じFDを返す可能性があります。実際、それらが同時ではない場合でも、最初のスレッドはselectを呼び出し、一部のFDは読み取り可能で、後でたとえばread、2番目のスレッドは2つの間でselectを呼び出します。 FDを2番目のスレッドで読み取り可能なものとして返します。

さて、質問の「目覚め」の部分に関連する部分はこれです:

選択された記述子のいずれも要求された操作の準備ができていない場合、pselect()またはselect()関数は、要求された操作の少なくとも1つが準備できるまで、タイムアウトが発生するまで、またはシグナルによって中断されるまでブロックします。

ここで明らかに上記の解釈は、同時に待機している呼び出しがすべて戻ることを示唆しています。

21
subsub

この質問のためにバグを見つけました。同じソケットで2つのスレッドを選択していて、fdがisset()として戻ってきたときにacceptを呼び出します。実際、selectは両方のスレッドに戻り、両方のスレッドでそのfdのfd isset()が返され、両方のスレッドがaccept()を呼び出し、一方が勝ち、もう一方のブロックが別の接続の着信を待機します。

したがって、実際には、selectは、同じfdに対してブロックしているすべてのスレッドに戻ります。

6
stu

それらはすべてウェイクアップし、すべて同じ結果値を返し、すべてFDセットに対して同じことを行う必要があります。彼らはすべて同じ質問をしているので、彼らはすべて同じ答えを得るはずです。

ここで引用したPOSIXドキュメントによると、select()が行うことになっていること、およびそれに関する私のわずか25年の経験は、読み取り可能、書き込み可能などのFDの数を返すことです。その瞬間。したがって、すべての同時select()呼び出しnotがすべて同じものを返すことは、完全に正しくありません。

select()関数は将来を予測できません。つまり、どのスレッドが実際に読み取りまたは書き込みを実行するのか、したがってどのスレッドがそれに成功するのかを予測できません。彼らは主張します。それは雷鳴の群れの問題です。

4
user207421