Selector.select не блокируется, как ожидалось - PullRequest
4 голосов
/ 31 августа 2011

В моем текущем проекте я заметил, что select() не блокируется, как ожидалось. Он вообще не блокируется и возвращается всегда, даже когда не было никакого ввода-вывода. Итак, я получил занятый процессор.

Регистрация всегда будет вызываться другим потоком, поэтому мне нужны блокировка и пробуждение.

Док говорит за selectNow():

Вызов этого метода очищает эффект любых предыдущих вызовов метода пробуждения.

Так что я вызываю метод в конце каждой итерации. нет успеха. Я не нашел ни примера, ни объяснения, как использовать selectNow для своих целей.

Что не так с кодом?


Вот мой пример кода, так что вы можете проверить это.

Кстати: еще один вопрос, связанный с переполнением стека, - ролевая модель моего кода. РЕДАКТИРОВАТЬ: пример исправлен! Это работает сейчас.

import java.io.IOException;
import java.net.*;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.concurrent.locks.ReentrantLock;

public class Test implements Runnable {
    ReentrantLock selectorLock = new ReentrantLock();
    Selector selector;
    boolean alive;

    @Override
    public void run() {
        SelectionKey key;
        Iterator<SelectionKey> keys;

        alive = true;
        try {
            while (alive) {
                selectorLock.lock();
                selectorLock.unlock();

                selector.select();
                System.out.println("select() returned");

                keys = selector.selectedKeys().iterator();
                // handle each "event"
                while (keys.hasNext()) {
                    key = keys.next();
                    // mark as handled
                    keys.remove();
                    // handle
                    handleKey(key);
                }
                //selector.selectNow(); // don't fix this
            }
        } catch ( IOException e ) {
            e.printStackTrace();
        }
    }

    private void handleKey(SelectionKey key)
        throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
        if (key.isConnectable()) {
            System.out.println("connecting");
            if ( channel.finishConnect() ) {
                key.interestOps(SelectionKey.OP_READ);
            } else {
                key.cancel();
            }
        } else if (key.isReadable()) {
            System.out.println("reading");
            // read and detect remote close
            channel.read(ByteBuffer.allocate(64));
        }
    }

    public void register(SelectableChannel channel, int ops, Object attachment)
        throws ClosedChannelException {
        selectorLock.lock();
        try {
            System.out.println("wakeup");
            selector.wakeup();
            channel.register(selector, ops, attachment);
        } finally {
            selectorLock.unlock();
        }
    }

    public Test()
        throws IOException {
        selector = Selector.open();
    }

    public static void main(String[] args)
        throws IOException {
        Test t = new Test();
        new Thread(t).start();

        SocketAddress address = new InetSocketAddress("localhost", 8080);
        SocketChannel channel = SocketChannel.open();
        channel.configureBlocking(false);
        channel.connect(address);

        t.register(channel, SelectionKey.OP_CONNECT, "test channel attachment");
    }
}

1 Ответ

9 голосов
/ 31 августа 2011

Не регистрируйте OP_READ, пока OP_CONNECT не запустит и finishConnect () вернет true.На этом этапе вы должны отменить регистрацию OP_CONNECT.

Аналогичным образом не регистрируйте каналы для OP_WRITE, пока у вас не будет чего-то написать.OP_WRITE всегда готов, за исключением случаев, когда буфер отправки сокета заполнен, поэтому он должен быть зарегистрирован только после , когда вы обнаружили это условие (write () возвращает ноль), и вы должны отменить его, как только оно сработает (если условие не произойдет снова).

И, наконец, OP_CONNECT и OP_WRITE - это то же самое под капотом, что с учетом того, что я только что сказал о OP_WRITE, объясняет ваши вращения селектора.

...