views:

338

answers:

4

I have a basic question. Why and how SelectableChannel's register method can be in blocking call. Let me provide a scenario.

I have created a Selector object in class Register as follows.

private static Selector selector = Selector.open();

I also have a method in same class(Register) to register the channel with the selector.

    public static SelectionKey registerChannel(SelectableChannel channel, 
           int ops) throws IOException {

       channel.configureBlocking(false);
       return channel.register(selector, ops);
    }

And there is another class named Request, which has method which reads the data from channels, processes and calls following method to register the channel.

selectonKey = Register.register(socketChannel, SelectionKey.OP_READ);

Here at this point the thread is blocked, not giving clue of what it is waiting for. I have verified that the selector is open. Please provide me some help to understand how can I resolve this. Is there any lock that I can release.

Any input would be appreciated.

Adding to what I described. Further tests revealed that if the Register.register method is called from the same thread, it is able to register but after that if some other thread tries to invoke the method, thread doesn,t move ahead.

A: 

Have you tried printing a stack trace of all threads in your program (using either kill -QUIT in Unix or Ctrl+Break in Windows or using the jstack utility)?

AbstractSelectableChannel contains a lock on which configureBlocking and register need to synchronize. This lock also is accessible through the blockingLock() method, and so another thread could potentially be holding the lock causing your register call to block indefinitely (but without a stack trace it's difficult to tell).

Adamski
A: 

If you use JConsole you can detect deadlocks from the Threads tab.

oxbow_lakes
A: 

You need to use a lock and manually synchronize.

In the same thread you are running the selector loop have a ReentrantLock:

final ReentrantLock selectorLock = new ReentrantLock();

Then when you need to register with the selector do something like this:

selectorLock.lock();
try {
    selector.wakeup();

    socketChannel.register(selector, 0, channel);
} finally {
    selectorLock.unlock();
}

Finally, during your loop that you are calling accept(), something like this:

selectorLock.lock();
selectorLock.unlock();

selector.select(500);

And then continue on with the rest of your logic.

Kevin Herron
+2  A: 

This is a basic feature of most NIO implementations that isn't obvious from the documentation.

You need to make all register calls from the same thread that is doing your selecting or deadlocks will occur. Usually this is done by providing a queue of registrations/deregistrations/interest-changes that is written to and then selector.wakeup() is called. When the selecting thread wakes up it checks the queue and performs any requested operations.

Darron