Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boost::asio, threads and synchronization

This is somewhat related to this question, but I think I need to know a little bit more. I've been trying to get my head around how to do this for a few days (whilst working on other parts), but the time has come for me to bite the bullet and get multi-threaded. Also, I'm after a bit more information than the question linked.

Firstly, about multi-threading. As I have been testing my code, I've not bothered with any multi-threading. It's just a console application that starts a connection to a test server and everything else is then handled. The main loop is this:

while(true)
{
    Root::instance().performIO(); // calls io_service::runOne();
}

When I write my main application, I'm guessing this solution won't be acceptable (as it would have to be called in the message loop which, whilst possible, would have issues when the message queue blocks waiting for a message. You could change it so that the message-loop doesn't block, but then isn't that going to whack the CPU usage through the roof?)

The solution it seems is to throw another thread at it. Okay, fine. But then I've read that io_service::run() returns when there is no work to do. What is that? Is that when there's no data, or no connections? If at least one connection exists does it stay alive? If so, that's not so much of a problem as I only have to start up a new thread when the first connection is made and I'm happy if it all stops when there is nothing going on at all. I guess I am confused by the definition of 'no work to do'.

Then I have to worry about synchronizing my boost thread with my main GUI thread. So, I guess my questions are:

  1. What is the best-practice way of using boost::asio in a client application with regard to threads and keeping them alive?
  2. When writing to a socket from the main thread to the IO thread, is synchronization achieved using boost::asio::post, so that the call happens later in the io_service?
  3. When data is received, how do people get the data back to the UI thread? In the past when I used completion ports, I made a special event that could post the data back to the main UI thread using a ::SendMessage. It wasn't elegant, but it worked.

I'll be reading some more today, but it would be great to get a heads up from someone who has done this already. The Boost::asio documentation isn't great, and most of my work so far has been based on a bit of the documentation, some trial/error, some example code on the web.

like image 744
Moo-Juice Avatar asked Jan 19 '11 11:01

Moo-Juice


2 Answers

1) Have a look at io_service::work. As long as an work object exists io_service::run will not return. So if you start doing your clean up, destroy the work object, cancel any outstanding operations, for example an async_read on a socket, wait for run to return and clean up your resources.

2) io_service::post will asynchronously execute the given handler from a thread running the io_service. A callback can be used to get the result of the operation executed.

3) You needs some form of messaging system to inform your GUI thread of the new data. There are several possibilities here.

As far as your remark about the documention, I thing Asio is one of the better documented boost libraries and it comes with clear examples.

like image 56
André Avatar answered Oct 03 '22 02:10

André


boost::io_service::run() will return only when there's nothing to do, so no async operations are pending, e.g. async accept/connection, async read/write or async timer wait. so before calling io_service::run() you first have to start any async op.

i haven't got do you have console or GUI app? in any case multithreading looks like a overkill. you can use Asio in conjunction with your message loop. if it's win32 GUI you can call io_service::run_one() from you OnIdle() handler. in case of console application you can setup deadline_timer that regularly checks (every 200ms?) for user input and use it with io_service::run(). everything in single thread to greatly simplify the solution

like image 27
Andriy Tylychko Avatar answered Oct 03 '22 02:10

Andriy Tylychko