playing around with tutorial codes to understand ioservice
Hi, I have been working on asio from the online documentation for more than a week but I am still confused about the io_service. Especially about what happens when we pass io_service to so many other things (timer, socket, chat_client etc.)? I hoped playing around with the codes in tutorial may help me in understanding. I modified the code a bit from timer3.cpp examplehttp://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/tutorial/tuttimer3..... (modified code is in attachment) When I add another io_service object, I was thinking one would run then the other one would start since in the comments of io_service.hpp it says * The run() function blocks until all work has finished and there are no * more handlers to be dispatched, or until the io_service has been stopped. but when I run two io_service objects io.run(); io2.run(); I get output from two of them interchangingly. (first print in each line is address of deadline timer, I added in print function to see which thread is running.) 0012FF04 0 0012FEE4 1 0012FEE4 2 0012FEE4 3 0012FF04 4 Could someone help me understand io_service class? (Maybe some pointers to old discussions could help.) I also read some papers about Proactor pattern, without too much help. Maybe example code can be supplied with more comments. I would also appreciate suggestions and pointers (probably in private emails to ozgur7 AT gmail com) to help me about implementing a simple command server (proxy). I am trying to implement a server to accept clients and run MySQL queries (example: look up name and password pair in a table) and pass results to clients. I am using connector/C++ for MySQL part, and that part seems very easy. However I am having difficulty in understanding asio. Do you think, I am overkilling for such a simple thing. (I thought it could pay back later when I needed to improve my program...) Thanks in advance, Best regards, Ozgur (Oscar) Ozturk www.DrOzgur.com +1 (614) 805-4370
It might help to think of a single io_service *instance* as a single event loop. When you invoke run() on instance X of an io_service from thread Y, then X is allowed to post notifications to thread Y when an event happens on that io_service. So, for example, if you have one io_service and you invoke run() from 5 threads on the same instance, then the all 5 threads will be participating in the event loop for this instance of io_service. It is undefined which thread will receive notification of an event, only that exactly 1 of the threads in the event loop will wake up when something happens. So if you have 2 io_service instances, then the output can be interleaved if you call run from multiple threads. In your program, you declare 2 io_services, but you actually only use one. Maybe this is a typo? io2 isn't even used, so io2.run() just returns instantly. I also rewrote your code a little. It helps to print out the time until expiration for each timer. boost::asio::io_service io,io2; boost::asio::deadline_timer* timer1; boost::asio::deadline_timer* timer2; void print(const boost::system::error_code& /*e*/, boost::asio::deadline_timer* t, int* count) { if (*count < 5) { ++(*count); t->expires_at(t->expires_at() + boost::posix_time::seconds(1)); std::cout << *count << ": " << ((t==timer1)?"timer1":"timer2") << ", t1exp: " << timer1->expires_from_now() << ", t2exp: " << timer2->expires_from_now() << std::endl; t->async_wait(boost::bind(print, boost::asio::placeholders::error, t, count)); } } int main() { int count = 0; timer1 = new boost::asio::deadline_timer(io, boost::posix_time::seconds(1)); timer2 = new boost::asio::deadline_timer(io, boost::posix_time::seconds(1)); std::cout << "[start]: t1exp: " << timer1->expires_from_now() << ", t2exp: " << timer2->expires_from_now() << std::endl; timer1->async_wait(boost::bind(print, boost::asio::placeholders::error, timer1, &count)); timer1->expires_at(timer1->expires_at() + boost::posix_time::seconds(1)); timer2->async_wait(boost::bind(print, boost::asio::placeholders::error, timer2, &count)); io.run(); io2.run(); std::cout << "Final count is " << count << "\n"; int discard; std::cin>>discard; return 0; } [start]: t1exp: 00:00:01, t2exp: 00:00:01 1: timer1, t1exp: 00:00:03, t2exp: 00:00:01 2: timer2, t1exp: 00:00:02, t2exp: 00:00:01 3: timer2, t1exp: 00:00:01, t2exp: 00:00:01 4: timer2, t1exp: 00:00:00, t2exp: 00:00:01 5: timer1, t1exp: 00:00:01, t2exp: 00:00:01 Final count is 5 Does this make it clearer why it's behaving the way it is?
Hi,
Thanks Zachary, yes, I have made a typo, thanks for pointing to it,
and for the explanation.
But it I have the same question for your code since we have a similar
(interleaved) output.
What I understood was, when we call io.run, main thread is suspended until
things assigned to it finishes.
(that is why in the examples the final count is not printed before an
io.run() completes, right?!)
so how come io2.run() is invoked from main thread (before io.run() finishes)
(and we can get interleaved results)?
Something I must be getting wrong.
TIA,
Best regards,
Ozgur (Oscar) Ozturk
www.DrOzgur.com
+1 (614) 805-4370
On Sat, Jul 11, 2009 at 5:33 PM, Zachary Turner
It might help to think of a single io_service *instance* as a single event loop. When you invoke run() on instance X of an io_service from thread Y, then X is allowed to post notifications to thread Y when an event happens on that io_service. So, for example, if you have one io_service and you invoke run() from 5 threads on the same instance, then the all 5 threads will be participating in the event loop for this instance of io_service. It is undefined which thread will receive notification of an event, only that exactly 1 of the threads in the event loop will wake up when something happens.
So if you have 2 io_service instances, then the output can be interleaved if you call run from multiple threads.
In your program, you declare 2 io_services, but you actually only use one. Maybe this is a typo? io2 isn't even used, so io2.run() just returns instantly. I also rewrote your code a little. It helps to print out the time until expiration for each timer.
boost::asio::io_service io,io2; boost::asio::deadline_timer* timer1; boost::asio::deadline_timer* timer2;
void print(const boost::system::error_code& /*e*/, boost::asio::deadline_timer* t, int* count) { if (*count < 5) { ++(*count);
t->expires_at(t->expires_at() + boost::posix_time::seconds(1));
std::cout << *count << ": " << ((t==timer1)?"timer1":"timer2") << ", t1exp: " << timer1->expires_from_now() << ", t2exp: " << timer2->expires_from_now() << std::endl;
t->async_wait(boost::bind(print, boost::asio::placeholders::error, t, count)); } }
int main() { int count = 0; timer1 = new boost::asio::deadline_timer(io, boost::posix_time::seconds(1)); timer2 = new boost::asio::deadline_timer(io, boost::posix_time::seconds(1));
std::cout << "[start]: t1exp: " << timer1->expires_from_now() << ", t2exp: " << timer2->expires_from_now() << std::endl;
timer1->async_wait(boost::bind(print, boost::asio::placeholders::error, timer1, &count)); timer1->expires_at(timer1->expires_at() + boost::posix_time::seconds(1));
timer2->async_wait(boost::bind(print, boost::asio::placeholders::error, timer2, &count));
io.run(); io2.run();
std::cout << "Final count is " << count << "\n";
int discard; std::cin>>discard; return 0; }
[start]: t1exp: 00:00:01, t2exp: 00:00:01 1: timer1, t1exp: 00:00:03, t2exp: 00:00:01 2: timer2, t1exp: 00:00:02, t2exp: 00:00:01 3: timer2, t1exp: 00:00:01, t2exp: 00:00:01 4: timer2, t1exp: 00:00:00, t2exp: 00:00:01 5: timer1, t1exp: 00:00:01, t2exp: 00:00:01 Final count is 5
Does this make it clearer why it's behaving the way it is? _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On Sat, Jul 11, 2009 at 5:35 PM, Ozgur Ozturk
Hi, Thanks Zachary, yes, I have made a typo, thanks for pointing to it, and for the explanation. But it I have the same question for your code since we have a similar (interleaved) output. What I understood was, when we call io.run, main thread is suspended until things assigned to it finishes. (that is why in the examples the final count is not printed before an io.run() completes, right?!) so how come io2.run() is invoked from main thread (before io.run() finishes) (and we can get interleaved results)? Something I must be getting wrong.
The typo is what's causing the interleaved results :) io2 is never being used. timer2 is attached simply to io. So you have 2 timers both using the same io_service. If I change the code so that timer2 uses io2, I get the following output: [start]: t1exp: 00:00:00.984375, t2exp: 00:00:01 1: timer1, t1exp: 00:00:02.984375, t2exp: 00:00:01 2: timer1, t1exp: 00:00:01, t2exp: -00:00:01.984375 3: timer1, t1exp: 00:00:01, t2exp: -00:00:02.984375 4: timer1, t1exp: 00:00:01, t2exp: -00:00:03.984375 5: timer1, t1exp: 00:00:01, t2exp: -00:00:04.984375 Final count is 5 In this case, it will actually call print with timer2 at the very end, but by then count is already 5, so it does not enter the if statement and just returns immediately.
Oh you had not fixed it in your code too...
Got it, thanks,
Best regards,
Ozgur (Oscar) Ozturk
www.DrOzgur.com
+1 (614) 805-4370
On Sat, Jul 11, 2009 at 6:43 PM, Zachary Turner
On Sat, Jul 11, 2009 at 5:35 PM, Ozgur Ozturk
wrote: Hi, Thanks Zachary, yes, I have made a typo, thanks for pointing to it, and for the explanation. But it I have the same question for your code since we have a similar (interleaved) output. What I understood was, when we call io.run, main thread is suspended until things assigned to it finishes. (that is why in the examples the final count is not printed before an io.run() completes, right?!) so how come io2.run() is invoked from main thread (before io.run() finishes) (and we can get interleaved results)? Something I must be getting wrong.
The typo is what's causing the interleaved results :) io2 is never being used. timer2 is attached simply to io. So you have 2 timers both using the same io_service. If I change the code so that timer2 uses io2, I get the following output:
[start]: t1exp: 00:00:00.984375, t2exp: 00:00:01 1: timer1, t1exp: 00:00:02.984375, t2exp: 00:00:01 2: timer1, t1exp: 00:00:01, t2exp: -00:00:01.984375 3: timer1, t1exp: 00:00:01, t2exp: -00:00:02.984375 4: timer1, t1exp: 00:00:01, t2exp: -00:00:03.984375 5: timer1, t1exp: 00:00:01, t2exp: -00:00:04.984375 Final count is 5
In this case, it will actually call print with timer2 at the very end, but by then count is already 5, so it does not enter the if statement and just returns immediately. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (2)
-
Ozgur Ozturk
-
Zachary Turner