java nio Selector wakeup - java

Please point/provide me an working example of selector.wakeup(); method between two threads.
I tried to create a simple program where a thread is waiting on selector.select() method. Second thread creates some sockets and tries to register with the selector; on which the first thread is blocked.
Hence I need to use selector's wakeup method, but somehow the first thread isnt doesn't come out of blocking mode.
The javadoc of wakeup method states:
If another thread is currently blocked
in an invocation of the
Selector.select() or
Selector.select(long) methods then
that invocation will return
immediately.
P.S There are few other work-around; one of them is select(timeout) but I am trying to figure out where the mistake is.
The psuedo-code:
FIRST THREAD:
static Selector selector = Selector.open();
while(true) {
int n = selectorGlobal.select();
selectorKeySet = selectorGlobal.selectedKeys().iterator();
while (selectorKeySet.hasNext()) {
selectionKey = selectorKeySet.next();
if (selectionKey.isReadable()) {
//do something
}
if(selectionKey.isAcceptable()) {
//accept
}
}
}
SECOND THREAD:
while (itr.hasNext()) {
data = (String) itr.next();
String IP = data.get(0);
String Port = data.get(1);
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(true);
boolean isConnected = socketChannel.connect(new InetSocketAddress(IP, Port));
ClassName.selector.wakeup();
SelectionKey selectionKey = SelectSockets.registerChannel(ClassName.selector,
socketChannel, SelectionKey.OP_READ);
}

You probably don't want to have the socket from Thread 2 be blocking if you're registering it in a selector (as selectors are meant for non-blocking I/O). I think it's also common practice to let the selector handle the connecting with OP_CONNECT (using SocketChannel.finishConnection()).
It also looks like you could have a potential race condition here. Imagine this series of events:
Thread 1: selector.select()
... time passes ...
Thread 2: Thread1.selector.wakeup()
Thread 1: checks keys for acceptability
Thread 1: checks keys for readibility
Thread 1: loop
Thread 1: selector.select()
Thread 2: try to register in the selector (but it's too late for this select())
I'd suggest having Thread 2 set up a SocketChannel, stash it away somewhere Thread 1 can get at it (make sure to be thread safe when you do this), then wake up the selector, let it check it's existing keys in Thread 1 and have Thread 1 register the new SocketChannel before it calls Selector.select() again.

Related

Delegating to a thread pool using a Selector and SelectionKeys

I am writing an application in which the main thread handles many connections through the use of a Selector and SelectionKeys. I have run into some trouble with a race condition when attempting to pass tasks off to the worker threads.
My main loop looks like this:
selector = Selector.open(); //Create selector
serverSocketChannel = ServerSocketChannel.open(); //Create socket channel, configure blocking, and bind
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(PORT));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //Register channel to selector
ByteBuffer buffer = ByteBuffer.allocate(8000);
while(true){
selector.select();
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while(iterator.hasNext()){
SelectionKey key = iterator.next();
if(key.isAcceptable()){
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
}
if(key.isReadable()){
taskList.add(new ReadTask(key));
}
if(key.isWritable()){
}
iterator.remove();
}
}
The idea here is that when a client tries to send data to the server, it receives a key with OP_READ interest and then creates a task with that key so that the threadpool can handle the read so as not to block the main thread.
The problem is that calling this loop continues during the process of the key being passed to a worker thread, and the entire time between when taskList.add(new ReadTask(key)); is called and the eventual key.channel().read(buffer) is called, the main thread is still iterating and sees the key as still being selected. After read is called on the key's channel, the key is marked as inactive and doesn't seem to be selected by the selector until another legitimate write from one of the clients prompts the key to be activated again.
Is there a way for me to mark the key so as not to have it added back to the list of selected keys by the selector without calling read? I've tried selector.selectedKeys.remove(key), but this yields a ConcurrentModification Exception.
You should either do the read in the select loop and then start the worker to process the data and prepare the response, or else remove OP_READ from the interestOps of the selection key until the response has been sent.

How to process requests asynchronously in Java server with I/O multiplexing?

Suppose I am writing a Java server, which communicates with clients over TCP/IP.
The server uses I/O multiplexing. There is a single thread T0, which waits on selector and handles client connections. For instance, if a connection is ready for read then T0 reads the data from the connection.
Suppose the server has read an incoming request and now it is ready to process it. Since the processing takes time the request is processed in another thread T1 and T0 returns to wait on the selector.
Suppose that T1 has finished the processing and created a response. Now T0 should start writing the response to the client connection. So my question is: how does T1 send the response to T0 ?
The same thread T1 should read, process and return the result to the client.
Here is an outline on how to do it with java nio api without linking the number of threads to the number of clients.
**//Thread T0** //wait for selection keys
...
Iterator it = selector.selectedKeys().iterator( );
while (it.hasNext( )) {
SelectionKey key = (SelectionKey) it.next();
// Is a new connection coming in?
if (key.isAcceptable( )) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel channel = server.accept()
// Set the new channel nonblocking
channel.configureBlocking (false);
// Register it with the selector
channel.register (selector, SelectionKey.OP_READ);
}
// Is there data to read on this channel?
if (key.isReadable( )) {
processRequest (key);
}
it.remove( );
}
...
ExecutorService service = Executors.newFixedThreadPool(50);
...
void processRequest(final SelectionKey key) {
**//Thread T1-T50** //deal with request
executorService.submit(new Runnable() {
SocketChannel channel = (SocketChannel) key.channel();
//read data from channel, process it and write back to the channel.
});
)
}
I recommend using a server thread that does nothing but blocking on ServerSocket.accept() and as soon as it accepts a connection, submits it to an ExecutorService. While in theory, you can have any number of threads, I would not do it since it makes your application vulnerable to DoS attacks. Instead, limit the maximum size of your thread pool and have it degrade gracefully if the server load goes over the top.
There is actually a small example of how to do this in the documentation for the ExecutorService.
Update: I might have misunderstood your question. As I understand now, you are aware of the solution suggested above but want to use synchronous multiplexing on purpose.
It would help to understand what kind of service your server provides and what is likely the limiting factor (CPU, disk I/O, networking, …).
You could assign a unique request ID to every incoming connection and insert a handler object into a map under that ID. Then, if a connection becomes ready, the network thread picks the respective handler and asks it to accept a certain amount of input / produce a certain amount of output. Whether this is applicable to your situation will of course depend on the service your server offers.

Avoiding high CPU usage with NIO

I wrote a multithreaded gameserver application which handles multiple simultaneous connections using NIO. Unfortunately this server generates full CPU load on one core as soon as the first user connects, even when that user is not actually sending or receiving any data.
Below is the code of my network handling thread (abbreviated to the essential parts for readability). The class ClientHandler is my own class which does the network abstraction for the game mechanics. All other classes in the example below are from java.nio.
As you can see it uses a while(true) loop. My theory about it is that when a key is writable, selector.select() will return immediately and clientHandler.writeToChannel() is called. But when the handler returns without writing anything, the key will stay writable. Then select is called again immediately and returns immediately. So I got a busy spin.
Is there a way to design the network handling loop in a way that it sleeps as long as there is no data to send by the clientHandlers? Note that low latency is critical for my use-case, so I can not just let it sleep an arbitrary number of ms when no handlers have data.
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
server.socket().bind(new InetSocketAddress(port));
Selector selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);
// wait for connections
while(true)
{
// Wait for next set of client connections
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> i = keys.iterator();
while (i.hasNext()) {
SelectionKey key = i.next();
i.remove();
if (key.isAcceptable()) {
SocketChannel clientChannel = server.accept();
clientChannel.configureBlocking(false);
clientChannel.socket().setTcpNoDelay(true);
clientChannel.socket().setTrafficClass(IPTOS_LOWDELAY);
SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
ClientHandler clientHanlder = new ClientHandler(clientChannel);
clientKey.attach(clientHandler);
}
if (key.isReadable()) {
// get connection handler for this key and tell it to process data
ClientHandler clientHandler = (ClientHandler) key.attachment();
clientHandler.readFromChannel();
}
if (key.isWritable()) {
// get connection handler and tell it to send any data it has cached
ClientHandler clientHandler = (ClientHandler) key.attachment();
clientHandler.writeToChannel();
}
if (!key.isValid()) {
ClientHandler clientHandler = (ClientHandler) key.attachment();
clientHandler.disconnect();
}
}
}
SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
The problem is here. SocketChannels are almost always writable, unless the socket send buffer is full. Ergo they should normally not be registered for OP_WRITE: otherwise your selector loop will spin. They should only be so registered if:
there is something to write, and
a prior write() has returned zero.
I don't see any reason why the reading and writing must happen with the same selector. I would use one selector in a thread for read/accept operations and it will always be blocking until new data arrives.
Then, use a separate thread and selector for writing. You mention you are using a cache to store messages before they are sent on the writable channels. In practice the only time a channel would not be writable is if the kernel's buffer is full, so it will rarely not be writable. A good way to implement this would be to have a dedicated writer thread that is given messages, and sleeping; it can be either interrupt()ed when new messages should be sent, or using a take() on a blocking queue. Whenever a new message arrives, it will unblock, do a select() on all writable keys and send any pending messages; only in rare cases will a message have to remain in the cache since a channel is not writable.

Killing a thread in Java using Thread.interrupt

I have a thread running in my Swing chat application to listen indefinitely through a socket for datagrams. When I close this application, I have the following code execute:
listenThread.interrupt();
socket.close();
However, interrupt doesn't seem to be stopping the thread, as when the socket closes, the loop continues listening, and throws exceptions since the socket has been closed. How do I get the thread to exit properly so that I can close the socket safely?
interrupt() cannot be used to interrupt an I/O operation such as socket reads or writes. To abort the I/O, closing the socket is the right way. After your thread receives the IOException it should check if it was interrupted in the meantime and then gracefully exit.
Example for the code in your I/O thread:
while( !Thread.currentThread().isInterrupted() ) {
try {
doRead();
} catch ( IOException ioe ) {
// Log exception or whatever
}
}
interrupt() only notifies the thread about someone's intention to stop it. It's up to the thread to properly exit. If thread is waiting on the monitor it will receive InterruptedException, otherwise you can check isInterrupted() on the current thread. However, if it's waiting on IO you may be out of luck and your only choice is to wait for socket time out to expire. Then you will check if thread is interrupted and close the socket.
If it's throwing an exception, catch it and exit the UDP read thread. Throwing an exception when the socket is closed from another thread is expected - make use of it!
Failing that, set the interrupted flag and make the UDP read() return by sending it a datagram on the local TCP stack from a socket in thread requesting the shutdown. UDP is a connectionless message service and is quite happy to receive a datagram from another thread on the same box. The datagram could contain a shutdown instruction, or you could check the isInterrupted flag after every read() return, just in case it's set.
I'm going to assume you've implemented this the easy way and done:
DatagramSocket s = new DatagramSocket( port );
DatagramPacket p = new DatagramPacket( new byte[256], 256);
s.receive( p );
Now, looking at the Javadoc, there's no way to get the DatagramSocket.receive() to throw an InterruptedException. Closing the socket is the only way to get it to stop listening.
A better implementation of this would have been to set a time out on the DatagramSocket using DatagramSocket.setSoTimeout( int ) to something small like 2 seconds, and then check if your server has been interrupted. So you'd end up with something like this for your server code ( doesn't handle exceptions ):
DatagramSocket s = new DatagramSocket( port );
s.setSoTimeout( 2000 ); // 2 second time out
while( running ){ // boolean running flag, check for interrupt here
try{
DatagramPacket p = new DatagramPacket( new byte[256], 256);
s.receive( p );
//do stuff
} catch ( SocketTimeoutException e ){
//timed out
}
}//end while

Java thread blocks while registering channel with selector while select() is called. What to do?

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.
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.
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, ops);
} 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.
This construct guarantees that the register() call will not block by ensuring that there is never another select() between corresponding wakeup() and register() calls.
I agree with #Darron's answer that you should pass register calls to the selector thread, but you should not use selector.wakeup as it would introduce race conditions (imagine selector thread was busying processing other registrations and your wakeup fail to wake up anyone). Luckily, Java NIO provided Pipe so that you can let the selector listen for both register calls and other events.
Basically, here's what needs to be done:
val registrationPipe = Pipe.open()
registrationPipe.source().configureBlocking(false)
registrationPipe.source().register(selector, SelectionKey.OP_READ)
// now start your selector thread
// now to register a call from other threads using message pleaseRegisterMe
registrationPipe.sink().write(pleaseRegisterMe)
// inside your selector thread
val selectionKey = iterator.next()
if (selectionKey.channel() === registrationPipe.source()) {
registrationPipe.source().read(pleaseRegisterMe)
// do something with the message pleaseRegisterMe and do the actual register
}
Here is a full working example.
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).
Register your channel from any thread:
synchronized (selectorLock2) {
selector.wakeup();
synchronized (selectorLock1) {
channel.register(selector, ops);
}
}
Your selector loop should look like this:
while (true) {
synchronized (selectorLock1) {
selector.select();
}
synchronized (selectorLock2) {}
....
}

Categories

Resources