According to the boost asio documentation, if I call close on a socket that has an asynchronous connect operation pending, the handler will be called "immediately" with an error code. From the documentation:
This function is used to close the socket. Any asynchronous send, receive or connect operations will be cancelled immediately, and will complete with the boost::asio::error::operation_aborted error.
But the handler is not actually called immediately/synchronously, it is called asynchronously when control returns to the io_service. Is it possible that my connect handler still gets called without an error code after I call close, if the connect actually succeeded and my handler callback has already been posted to the io_service?
The documentation states that the outstanding operations will be canceled immediately, not that they will be called immediately.
It is possible that the connect operation has already completed, and the handler is queued in the io_service for deferred invocation with its error_code as boost::system::errc::success. It may be worth consider checking if the socket is_open() in the completion handler, as done in this answer. For more details on this behavior, see this answer.
The operations will be cancelled immediately, but the handler doesn't get called synchronously. If a "normal" completion handler is already in the queue when you call close(), it definitely will be invoked, and you won't get "operation_aborted".
Related
I want to access Redis and do a GET on two machines simultaneously. I'll use the first result I get and cancel the other call.
What I'm wondering is whether cancelFunc() breaks a go function immediately or whether it will wait for a specific event to happen before it notices the signal. The documentation just says:
Calling the CancelFunc cancels the child and its children, removes the parent's reference to the child, and stops any associated timers.
That doesn't say whether it happens immediately or whether a special cancellation point needs to be reached.
Any documentation I missed about that particular point?
Canceling a context simply closes its Done channel, it doesn't "kill" a goroutine or anything like that. Code that executes under the context has to do a select to notice the closure of the Done channel and abandon whatever work it's doing.
However in many cases this work is already done for you. If the redis client method you're using to make requests accepts a context, then it's safe to assume that if that context is canceled, the client will handle the cancellation and the method will immediately return an error of context.Canceled — all you need to do is handle that error by quitting what you're doing.
I'm using WinHTTP in sync mode, without passing the WINHTTP_FLAG_ASYNC flag, and I thought that the callback is always being called synchronously. That is indeed what's happening most of the time, but sometimes, when calling WinHttpCloseHandle, the callback isn't called with the WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING notification right away. Instead, it's being called afterwards from a different thread.
It that expected behavior? Why does it become async for some cases, if the seesion is sync? I know how to fix it (waiting for the WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING notification if I don't get it right away), but I don't understand why that's the behavior that I'm seeing.
WinHTTP does not promise synchronous "same thread" callbacks in synchronous mode. On the contrary, MSDN states the opposite:
The callback function must be threadsafe and reentrant because it can be called on another thread for a separate request, and reentered on the same thread for the current request. It must therefore be coded to handle reentrance safely while processing. When the dwInternetStatus parameter is equal to WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, the callback does not need to be able to handle reentrance for the same request, because this callback is guaranteed to be the last, and does not occur when other messages for this request are handled.
This means that the symptom you are seeing is basically behavior by design and is not related to async mode: some callback calls might be sent to you from worker threads and then thread racing might reach your code late in your callback. You need to take this into consideration and either ignore those late calls, or synchronize with them, or reset callbacks early enough explicitly to not receive late notifications.
Regarding WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING specifically MSDN explains what you can rely on exactly (see quote above).
Say first I call async_connect on a newly constructed tcp::socket. Before the handler of async_connect is called, I call async_read/writes on the same socket. Will them wait for the connection or fail immediately because the socket has not connected?
Since async_connect performs asynchronously, your scenario has race-condition - so it may occasionally work or fail, depending on timings. In order to begin async. i/o on a socket, one should wait first for async_connect completion handler - just like described in the Asio documentation.
That's said, you can design a class that will accept async. operations as functors, store them in a queue, and internally chain/invoke them in the correct order.
I'm using Oracle ODP.Net for enqueue and dequeue.
Process A : Enqueue
Process B : Dequeue with MessageAvailable event
If Process A and B are running, there is no problem. On the "Process B", the event is always fired.
But, if "Process B" is off and "Process A" is on, when "Process B" restarts, the queues inserted during the off time are lost.
Is there an option for to fire the event for all queues inserted in the past ?
Many Thanks
There seem to be two approaches to address this issue:
Call the Listen() method of the OracleAQQueue class (after registering for message notification) to pick up "orphaned" messages sitting in the queue. Note that Listen() blocks until a message is received or a timeout occurs. So you'd want to specify a (short) timeout to return back to the processing thread in the event no messages are on the queue.
Call the Dequeue() method and trap Oracle error 25228 (no message available to dequeue). See the following thread from the Oracle support forums: https://forums.oracle.com/forums/thread.jspa?threadID=2186496.
I've been scratching my head on this topic. If you still have to "manually" test for new messages, what is the benefit of using the MessageAvaiable event callback in the first place? One route I've pondered is to wrap the Listen() method in an async call so that the caller isn't blocking on the thread (until a message is received or a timeout occurs). I wrapped Listen() and Dequeue() in a custom Receive() method and created my own MessageReceived event handler to pass the message details to the calling thread. Seems somewhat redundant, since ODP.NET provides the out-of-box callback, but I don't have to deal with the issue you describe (or write code to "manually" test for "orphaned" messages.
Any comments/thoughts on approach are welcomed.
I've been looking at this one too and have ended up doing something similar to Greg. I've not used the Listen() method though as I don't think it offers me anything over and above a simple Dequeue() - Listen() seems to be beneficial when you want to listen on behalf of multiple consumers, which in my instance is not relevant (see Oracle Docs).
So, in my 'Process B' I first register for notifications before initiating a polling process to check for any existing messages. It doesn't Listen(), it just calls Dequeue() within a controlled loop with a Wait period of a couple of seconds set. If the polling process encounters an Oracle timeout the wait period has expired and polling stops. I may need to consider dealing with timeouts if the wait period hasn't expired (though not 100% sure this if this is likely to happen).
I've noticed that any messages which are enqueued whilst polling will call the message notification method but by the time this connects and tries to retrieve the message the polling process always seems to have taken it. So inside the message notification method I capture and ignore any OracleExceptions with number 25263 (no message in queue <...> with message ID <...>).
CancelIo() is supposed to cancel all pending I/O operations associated with the calling thread. In my experience, CancelIo() sometimes cancels future I/O operations as well. Given:
ReadFile(port, buffer, length, &bytesTransferred, overlapped);
If I invoke CancelIo(port) immediately before the read, GetQueuedCompletionStatus() will block forever, never receiving the read operation.
If I invoke CancelIo(port) immediately after the read, GetQueuedCompletionStatus() will return 0 with GetLastError()==ERROR_OPERATION_ABORTED
If I invoke CancelIo(port) and there are no pending or subsequent reads, GetQueuedCompletionStatus() will block forever.
The key point here is that there is no way to detect when CancelIo() has finished executing. How can I ensure that CancelIo() is done executing and it is safe to issue further read requests?
PS: Looking at http://osdir.com/ml/lib.boost.asio.user/2008-02/msg00074.html and http://www.boost.org/doc/libs/1_44_0/doc/html/boost_asio/using.html it sounds like CancelIo() is not really usable. Must customer requires Windows XP support. What are my options?
NOTE: I am reading from a serial port.
CancelIo() works fine. I misunderstood my code.
Upon further investigation it turns out that the code was invoking CancelIo() followed by ReadFile() with a timeout INFINITE. The completion port was never getting notified of the read because the remote end was never sending anything. In other words, CancelIo() did not cancel subsequent operations.
I found some eye-opening documentation here:
Be careful when coding for asynchronous I/O because the system reserves the right to make an operation synchronous if it needs to. Therefore, it is best if you write the program to correctly handle an I/O operation that may be completed either synchronously or asynchronously. The sample code demonstrates this consideration.
It turns out that device drivers may choose to treat an asynchronous operation in a synchronous manner if the data being read is already cached by the device driver. Upon further investigation, I discovered that when CancelIo() was being invoked before ReadFile() it would sometimes cause the latter to return synchronously. I have no idea why the completion port was never getting notified of ReadFile() after a CancelIo() but I can no longer reproduce this problem.
The completion port is signaled regardless of whether ReadFile() is synchronous or asynchronous.
Wait on (possibly with zero timeout) overlapped.Handle. It will be set whether the operation is completed or cancelled.
If you're already using overlapped operations, why do you need to cancel I/O at all? The entire concept of 'cancelling' an in-flight I/O operation is really race-prone, and totally subject to the underlying device stack you're trying to write to; really the only time you'd want to do this is to unblock another thread who is waiting on the completion of that I/O.
It is possible to write asynchronous I/O code without CancelIo function. The question depends on the scenario you are using CancelIO. Let's say that you need to implement file reading thread. Thread pseudo-code:
for(;;)
{
ReadFile(port, buffer, length, &bytesTransferred, overlapped);
WaitForMultipleObjects( overlapped event + stop event);
if ( stop event is signaled )
break;
if (overlapped event is signaled )
handle ReadFile results
}
Such thread reads file (socket, port etc.) using overlapped I/O. Most of the time it waits on WiatForMultipleObjects line. It wakes up when new data is available, or stop event is signaled. To stop this thread, set stop event from another thread. CancelIO is not used.