5

私が書くなら:

int selectedChannels = selector.select();
selectedKeys = selector.selectedKeys(); を設定します。
if ( selectedChannels != selectedKeys.size() ) {
    // Selector.wakeup() の呼び出しにより Selector.select() が返されました
    // 同期も同様です。
}
// 選択したチャネルの処理を続行します。

モーニングコールを正しく検出しますか?

背景情報:

ほとんどの場合、パケットを受信して​​ファイルに保存するサーバーを作成しています。アプリケーションが自分自身に特別なパケットを送信する必要があることはほとんどありません。このために、(別のスレッドから) サーバーソケットへの接続を開始します。

SocketChannel channel = SocketChannel.open();
channel.configureBlocking( false );
channel.connect( new InetSocketAddress( InetAddress.getLocalHost(), PORT ));
selector.wakeup();
SelectionKey キー = channel.register( セレクター、SelectionKey.OP_CONNECT );

問題は、メインスレッドがすでに Selector.select() にある場合、SelectableChannel.register() がブロックされる可能性があることです。これが起こらないようにするために、私は Selector.wakeup() を呼び出しています。これにより、メイン スレッドが select() から途中で戻ります。他のスレッドが登録呼び出しを完了する機会があることを確認するには、メイン スレッドを同期する必要がありますが、select() から戻るたびにそれを行う必要があります。wakeup() 呼び出しのために select() から返されたかどうかを検出できれば、この場合に最適化できます。

したがって、理論的にはトップ コード スニペットは機能するはずですが、特定されていない動作に依存しているため、機能するだけなのかどうか疑問に思っていました。

ヒントをありがとう。

4

4 に答える 4

3

Selector#select()との契約に従って、提案されたスニペットは原則としてまったく機能しないと思いSelector#selectedKeys()ます。セレクターから:

  • 選択されたキーセットは、各キーのチャネルが、前の選択操作中にキーの対象セットで識別された操作の少なくとも 1 つに対応できることが検出されたようなキーのセットです。このセットは selectedKeys メソッドによって返されます。
public abstract int select(ロングタイムアウト)
                IOException をスローします
    戻り値:
        準備完了操作セットがあったキーの数 (ゼロの場合もある)。
        更新しました

私が読んだように、セットのサイズは、定義によってselectedKeys返される数値と常に等しくなければなりません。selectあなたもお持ちかもしれませんが、実装によってはドキュメントに完全に従っていないことに気付きselectedKeysましたselect。への呼び出しが原因で select がウェイクアップしたことを示す他の唯一の指標はwakeup、キーの数がゼロであることです。ただし、どちらの方法も信頼できません。

これを処理する通常の方法は、暗に示されているように、同時実行制御を使用することです。ここでは実行時間を気にしません。これは時期尚早の最適化の典型的な例です。

1 桁のマイクロ秒単位の許容誤差を本当に心配していない限り、速度の低下に気付くことはありません。また、そのレベルの許容誤差を心配している場合は、いずれにせよ、aSelectorは十分に信頼できるものではありません。

ReentrantLock適切な同時実行性を実現するためにa を使用する、これに対する通常のメカニズムの例を次に示します。

ReentrantLock selectorGuard;
Selector selector;

private void doSelect() {
    // Don't enter a select if another thread is in a critical block
    selectorGuard.lock();
    selectorGuard.unlock();

    selector.select();
    Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();

    while(keyIter.hasNext()) {

        SelectionKey key = keyIter.next();
        keyIter.remove();

        // Process key
    }
}

private void addToSelector() {

    // Lock the selector guard to prevent another select until complete
    selectorGuard.lock();

    try {
        selector.wakeup();

        // Do logic that registers channel with selector appropriately

    } finally {
        selectorGuard.unlock();
    }
}
于 2008-12-02T17:08:16.577 に答える
0

あなたのコードが一般的に機能する理由がわかりません。

volatileafterをチェックしてみませんselectか?

于 2008-12-02T12:02:35.633 に答える
-1

セレクターがウェイクアップした唯一の理由がウェイクアップ コールによるものかどうかは、はっきりとはわかりません。また、ソケット アクティビティがある場合もあります。

そのため、ウェイクアップの呼び出し元にも、揮発性ブール値を設定して注意を喚起するなどのことを行わせる必要があります。セレクター ループは、起動するたびにこのブール値をチェックできます。

于 2008-12-02T13:43:27.270 に答える