[asio] async write handler is not called until the socket is not closed
Hi! I've got very strange problem - handler passed to async_write is not called in time. What I mean - it is called only when socket is closed - then handler is invoked many times. Sometimes it is so, sometimes everything is fine. The main thing is that traffic exists. I mean - async writes get completed. I call io_service.run() in proper time, etc. Another moment - the first two times the handler is invoked, but not more. As I guess, the problem is somewhere in my code. But I ask you to point to probable reasons of such behaviour that breaks asio rules..
But I ask you to point to probable reasons of such behaviour that breaks asio rules..
According to your description, probable reason is a blocked io_service thread. Maybe in some situation one of the handlers (which are called from within io_serivce thread) do not return - then any subsequent handler won't be invoked. Probably the blockage is released after you close the socket - due to some design issues, so at this point all the queued handlers get invoked.
Thank you for reply, Igor! But I guess the io_service thread is not blocked. Becase: a) I have 2 threads. One pushes messages to queue. Second is io_service.run() with timer that async_reads from socket and async_writes the message queue to socket b) program continues working. Async_read handler is called. Writing is also completes (server, written in the same way - receives all data) + timers "onTick"s are also invoked. So, all IO is done within 1 thread and if it will be blocked then all IO will stop, as I understand, but only async_write handlers are not invoked. Any thoughts are welcome. It seems I've got very rare bug in my program))
According to your description, probable reason is a blocked io_service thread.
Ok, I made some investigation and found, that the situation is only observed under high cpu loads. Let's imagine one IO thread. on timer event (each second) it pushes X messages to socket with async_write. Also, at this time, the IO thread receives Y messages with async_read through the same socket. Is there any limit in pushing messages with async_write? What it is? Windows XP sp2, boost 1.38.0 Thank you!
Let's imagine one IO thread. on timer event (each second) it pushes X messages to socket with async_write. Also, at this time, the IO thread receives Y messages with async_read through the same socket. Is there any limit in pushing messages with async_write? What it is?
I know nothing about such a limit, but I suspect another issue in your approach: your description sounds like you don't ensure that async_write is complete (i.e. the handler is called) before issuing another one. If my assumption is correct, you might run into various problems, as the order of execution of your async_writes is undefined. The same applies to async_read's. The correct approach would be like this: // pseudo-code!! class connection : public enable_shared_from_this<connection> { public: void send(Data data) { socket_.get_io_service().post(bind(&connection::syncSend, shared_from_this(), data)); } private: void syncSend(Data data) { // enqueue the data and ensure the write is active someContainer_.push_back(data); activeWrite(); } void activateWrite() { if (!activeWrite_ && unsentDataExists) { activeWrite_ = true; socket_.async_write(allTheData, bind(&connection::sent, shared_from_this(), _1)) } } void sent() { activeWrite_ = false; activateWrite(); } };
aha.. I understand. Simply, you offer me to create my own queue. I will do so! :) but the question - so it is bad to make many async_write calls without waiting for handler call? As I thought - my async write requests will be simply pushed in some kind of queue and processed somewhen :) But you say: async_write - wait for handler - handler called - async write .. will investigate this. Thank you, Igor!
It works now! Igor, you are the best! :) Conclusion: the program flow must be: async_write - do smth - write handler called - async write - do smth - ...
It works now! Igor, you are the best! :)
I'm glad I was helpful.
Conclusion: the program flow must be:
async_write - do smth - write handler called - async write - do smth - ...
Yes, only one async_XXX should be in progress at a time (for the same socket/buffer). The primary problem with multiple async_write's is the following: while async_write guarantees that its handler is invoked only after *all* the data is sent or if an error occurs, it does NOT guarantee that all the buffer is sent at once. Now imagine you issue 2 async_write's: one for a buffer containing "12345678" and another one for "abcdefg". The both will be sent successfully, but your peer might receive the following data: "123ab456cdefg78" - depending on the timing, data-size, and network conditions. As for the problem you encountered - I don't exactly realize how multiple async_write's could cause it, but since fixing the above issue fixed your problem as well, I guess it's not worth investigating it further :).
participants (2)
-
Igor R
-
Roman Shmelev