2009-10-01 15 views
5

私は、非同期アプリケーションが、操作がスケジュールされているソケットを介していくつかのスレッドを実行し、非同期に実行しています。マルチスレッドソケットアプリケーションで同じfd番号の再利用を避ける

私は、一度ソケットを介して読み取り操作をスケジュールし、最初の操作が実行を開始する前にソケットが閉じられて(別の操作で他のピアによって)再開されると状況を回避しようとしています適切なファイル記述子が間違ったピアです。

問題は、(accept(); close(); accept())が両方のaccepts()で同じfdを返すため、上記の状況につながる可能性があります。

私はそれを避ける方法を見ることができません。

ヒント?

+0

なぜ、あるスレッドのブロッキングが別のスレッドによって閉じられているのですか? –

+0

非同期システムの性質は、あるオペレーションが読み込み、別の書き込みが実行され、別のオペレーションが終了し、すべてが異なるスレッドで実行される可能性があります。 –

+2

あなたのアプローチについて考え直してください。通常、接続を受け入れる単一のスレッドがあり、それらを処理するスレッドが生成されます。これらのスレッドは接続を終了する責任があり、他のスレッドはその接続にもアクセスすることはありません。 –

答えて

3

いいえ、答えが見つかりました。

ここでは、accept()を呼び出して使用可能な最低のfdを取得し、dup2(6,1000)やclose(6)のような数値で複製すると、fdの範囲を制御できるようになりますあなたが使う。

次の受諾は6かそれと同様で、私たちはdup2(6,999)となります。あまりにも低くなったら、それを減らして再設定してください。

受け入れは常に同じスレッドで行われ、dup2とcloseは受け入れられるよりも高価ではないので、常にそこで行われます。これは私のニーズに最適です。

2

どのようにソケットを管理していますか?あなたはどんなことができ、複数のスレッドを持っているように聞こえる:

  1. accept着信接続
  2. close既存の接続
  3. あなたが道を必要とするようですね新しい発信接続

を作ります周囲に浮かぶさまざまなソケットへのアクセスを仲介します。ソケットがまだ使用されている間にソケットを閉じるのを防ぐmutexに各ソケットを関連付けることを考えましたか?それとも、すべてのスレッドがそれを使って完了するまで他のスレッドが閉じるのを防ぐ原子参照カウントを持つstructに各ソケット記述子を入れますか?

+0

私はそうすることができましたが、このロックフリーなシステムにmutexを追加することは、私が避けようとしていることです。 最高のことは、acceptがfdを順番に与えないことを保証することですが、私はそれが起こっているのを見ることはできません。 –

+0

@Arkaitz - 私が言及した第二の解決策は、あなたにとって良いかもしれません。参照カウンタを持つ構造体にソケットを保持し、ゼロ以上の参照カウントを持つソケットをスレッドで閉じることはできません。すべてのスレッドがロックされるまでロックされず、ソケットは閉じられません。 –

1

ソケットは5タプル{local-addr、local-port、remote-addr、remote-port、proto}ですので、イベント/ハンドラのルーティングにfdの代わりにこれらのプロパティを使用できる場合は、 fdの衝突を避けてください。

別のオプションは、すべてのクローズ()/受け入れる()操作をシリアライズすることです(優先順位を?)彼らは

+1

私はまだ構造体を保護するためにmutexを必要とします。システムをもっと遅くし、私がそこにロックするのを避けようとしているエッジ状況になってしまいます。 –

0

各ソケットのために(など、読み取り/書き込み)保留中の操作のカウントを保持を混在することはできませんようにソケット上に保留中のクローズ要求があるかどうかも確認します。終了する前に、まず保留中の操作があるかどうかを確認します。存在する場合は、代わりにコールシャットダウンを実行し、保留中の操作数が0に達したときにクローズするだけです。

1

私はそのような問題が起こるかもしれないことに気づいていませんでした。

私が考えることができる唯一の答えは、ソケットが終了したことを知らせるためにclose()を使用しないことです。 1つの解決方法は、shutdown()を使用して接続を終了することです。その後、参照カウントを使用して安全にソケットを閉じることができます。

+0

'close'関数は根底にあるOSのソケット参照カウントを減らします。' shutdown'は強制的にcloseを強制し、EOF/FINをピアに送ります。詳細については、この記事を参照してください:http://stackoverflow.com/questions/409783/socket-shutdown-vs-socket-close/598759#598759 –

+0

あなたが掲示したリンクで述べたように、shutdown()はソケットを閉じません通信を終了するだけである。 Shutdown()は、保留中の(または将来の)I/O操作の失敗を引き起こしますが、FDの割り振り解除は行われないため、上記の問題は発生しません。オペレーションが失敗した場合、操作を実行するスレッドは、スレッドがソケットを受け取ったときに以前に増分されていた参照カウントをデクリメントし、ゼロになるとソケットを閉じます。明らかに、このrefcountはOS refcountではなく、プログラムで実装されたものです。 – TrayMan

+0

参照カウントについて心配する必要はなく、読み取り操作が失敗した場合はソケットを閉じるだけです。 – atomice

1

よく知られているfd値にdup2()を使用することにはまだ注意が必要です。 dup2()は、dupされる前にターゲット上でクローズを実行することを忘れないでください。 1000個のファイルが開かれ始めると、関係のないスレッドと無関係なI/Oを実行するスレッドと競合する可能性があります。

あなたが主張している制約を考えると、私はmutex内でdup()(dup2()ではない)を使用します。 (おそらくそれについて懸念している場合、fdのミューテックスがあります。)

+0

これは&dup2を受け入れ、すべて同じスレッド上で常に実行されます。だから私はMAX_FDを10に近づけてからやり直すことができました。私たちがやり直したので、MAX_FDを閉じたときにfupdをdup2()にポーズさせることは実際には考慮されません。 –

+0

しかし、関係のないファイルを開いていないことを証明できますか?または、あなたの代わりにいくつかの図書館が何かをしているのでしょうか?自然に発生するFDの数が最終的に1000に達することはないことを証明できますか?たぶんあなたはこれらのことを保証することができますが、このようなことはあなたのアプローチでは緊張してしまいます。 – asveikau

関連する問題