How to establish a connection between thread processing and a SocketChannel selector thread?

Consider the request-response protocol.

We create a thread to execute a select() loop to read and write to a received non-blocking SocketChannel . It might look something like this:

 while (!isStopped()) { selector.select(); Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator(); while (selectedKeys.hasNext()) { SelectionKey selectedKey = selectedKeys.next(); selectedKeys.remove(); Context context = (Context) selectedKey.attachment(); if (selectedKey.isReadable()) { context.readRequest(); } else /* if (selectedKey.isWritable()) */ { context.writeResponse(); } } } 

where Context is just a container for the corresponding SocketChannel , a buffer and logic to read into and write from it. readRequest might look like

 public void readRequest() { // read all content socketChannel.read(requestBuffer); // not interested anymore selectionKey.interestOps(0); executorService.submit(() -> { // handle request with request buffer and prepare response responseBuffer.put(/* some response content */); // or set fields of some bean that will be serialized // notify selector, ready to write selectionKey.interestOps(SelectionKey.OP_WRITE); selectionKey.selector().wakeup(); // worried about this }); } 

In other words, we read from the socket channel, fill up some buffer and pass processing to another thread. This thread performs the processing and prepares the response that it stores in the response buffer. He then notifies the selector that he wants to write and wakes up.

The javadoc for Selector#wakeup() does not mention any events - before the relationship, so I worry that the selector stream can see the response buffer (or some intermediate object) in an inconsistent state.

Is this a possible scenario? If so, what is the correct way to pass the response that should be written to the SocketChannel stream by the Selector loop stream? (Posting the response through some volatile field? Using the SelectionKey attachment? Another form of synchronization?)

+5
source share
2 answers

The documentation in Selector reads as follows:

Selection operations are synchronized on the selector itself, on the set of keys, and on the selected key set in this order.

occurs before relationships are defined in the Java Language Specification, chapter 17 , including the inclusion of synchronization with relationships.

However, you must correctly synchronize the attached object. This is your goal, this is your duty. Assuming that only the code is written to the responseBuffer in the executor stream, and only the selector stream reads it after you say that you are interested in the availability of the record, you have enough synchronization.

What may surprise you is that you get this synchronization from interestOps(...) , even up to wakeup() .


In my experience, if you find it difficult to find the correct synchronization using the library utilities (in this case, the selector), it is better to synchronize your object yourself, for example, with the synchronize operator on the object itself, ReentrantLock , another other synchronization object that you use on your object operations , etc. You lose a little performance (in most cases, insignificantly if you do not use the unit in the guarded section) to keep calm.

+2
source

First, you do not need to notify the selector of the desire to write. You just write. Only in the case when the record returns zero, you need to use the selector or its stream.

Secondly, the connection between events occurs as a result of choosing three levels of synchronization, if you also perform synchronization, as shown below.

Your code may block when calling interestOps() if a selector is currently selected. Javadok does not exclude the possibility. You need to complete the operations in the correct order:

  • wake up.
  • Sync selector.
  • Call interestOps() .

The combination of (2) and its own internal synchronization of the selector establishes any necessary actions before the relationship.

+3
source

Source: https://habr.com/ru/post/1272421/


All Articles