LINUX.ORG.RU

Регистрация в Selector из другого потока

 , ,


0

2

Я хочу написать класс, который работал бы с несколькими сокетами в одном потоке. Для этой цели как нельзя лучше подходят SocketChannel и Selector.

С серверной часть проблем нет:

        Selector selector = SelectorProvider.provider().openSelector();
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.socket().bind(socketAddress);
        serverSocketChannel.register(selector, serverSocketChannel.validOps());

        try {
            while (selector.select() > -1) {
                Iterator<SelectionKey> selectionKeyIterator = selector.selectedKeys().iterator();
                while (selectionKeyIterator.hasNext()) {
                    SelectionKey selectionKey = selectionKeyIterator.next();
                    selectionKeyIterator.remove();

                    if (selectionKey.isValid()) {
                        if (!handleSelectionKey(selectionKey)) {
                            logger.debug("Unhandled selection key: " + selectionKey.hashCode() + ", " + selectionKey.readyOps());
                        }
                    }
                }
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }

Все по секретным документам с хабра =) Пришел новый клиент - обработали isAcceptable.

Проблема с клиентской частью. Допустим я хочу иметь возможность подключаться к нескольким сокетам и обрабатывать их в одном потоке.

Запускаю в одном потоке:

while (selector.select() > -1)
Теперь если из другого потока я вызову:
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
        socketChannel.connect(socketAddress);
        socketChannel.register(selector, socketChannel.validOps());
И на register мы зависнем, ибо select захватил монитор и не отпускает его. Полагаю, что регистрироваться мы должны в том же потоке, где и происходит обработка select. Наверное нужно перед запуском цикла опроса Select зарегистрировать в нем на прослушивание своей операции аля WantToConnect, при возникновении необходимости подключиться к новому сокету из другого потока каким-то образом будить Selector, сообщать ему что пришло данное событие. Каким образом это можно сделать?

Опыт показывает что с Selector лучше работать в одном потоке. Сделай concurrent queue, и забрасывай туда задачи. На каждом цикле обработки событий разбирай эту очередь. Чтобы прервать Selelector надо у него позвать метод wakeup.

maxcom ★★★★★
()
Ответ на: комментарий от maxcom

Да, этот способ мне первым пришел в голову. Но я думал, что можно решить данную задачу единообразно обрабатывая события через Selector. Тогда не пришлось бы проверять очередь, а так же тестировать SelectionKey. Но нет, так нет.

Большое спасибо за ответ.

popov-aa
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.