37

I am currently trying to use boost::asio for some simple tcp networking for the first time, and I allready came across something I am not really sure how to deal with. As far as I understand io_service.run() method is basically a loop which runs until there is nothing more left to do, which means it will run until I release my little server object. Since I allready got some sort of mainloop set up, I would rather like to update the networking loop manually from there just for the sake of simplicity, and I think io_service.poll() would do what I want, sort of like this:

void myApplication::update()
{
     myIoService.poll();
     //do other stuff
}

This seems to work, but I am still wondering if there is a drawback from this method since that does not seem to be the common way to deal with boost::asios io services. Is this a valid approach or should I rather use io_service.run() in a non blocking extra thread?

moka
  • 4,353
  • 2
  • 37
  • 63

3 Answers3

43

Using io_service::poll instead of io_service::run is perfectly acceptable. The difference is explained in the documentation

The poll() function may also be used to dispatch ready handlers, but without blocking.

Note that io_service::run will block if there's any work left in the queue

The work class is used to inform the io_service when work starts and finishes. This ensures that the io_service object's run() function will not exit while work is underway, and that it does exit when there is no unfinished work remaining.

whereas io_service::poll does not exhibit this behavior, it just invokes ready handlers. Also note that you will need to invoke io_service::reset on any subsequent invocation to io_service:run or io_service::poll.

embedded
  • 51
  • 7
Sam Miller
  • 23,808
  • 4
  • 67
  • 87
  • 12
    `io_service` is not necessarily stopped after `io_service::poll` returned. Why need `io_service::reset` before subsequent `io_service::run` or `io_service:poll`? – updogliu Jan 11 '14 at 00:45
  • 1
    1+ for io_service::reset. If `run` doesn't find any work, `_stopped` is set to `true` which prevents any future added tasks to be handled. `reset` sets `_stopped` back to `false`. – JMRC Dec 24 '20 at 02:30
  • Yeah `io_service::reset` was referring to `io_service::run` in particular – atlex2 Aug 16 '22 at 15:25
3

A drawback is that you'll make a busy loop.

while(true) {
    myIoService.poll()
}

will use 100% cpu. myIoService.run() will use 0% cpu.

myIoService.run_one() might do what you want but it will block if there is nothing for it to do.

Kurt
  • 2,339
  • 2
  • 30
  • 31
  • 3
    you would indeed prefer run in this simplistic case but in the situation where an event loop already exists (say it's doing background rendering or other things in spare cycles) then poll would be preferred as you don't want the game coming to a halt every time run() blocks. – Brian Jack Nov 12 '14 at 18:27
1

A loop like this lets you poll, doesn't busy-wait, and resets as needed. (I'm using the more recent io_context that replaced io_service.)

while (!exitCondition) {
    if (ioContext.stopped()) {
        ioContext.restart();
    }
    if (!ioContext.poll()) {
        if (stuffToDo) {
            doYourStuff();
        } else {
            std::this_thread::sleep_for(std::chrono::milliseconds(3));
        }
    }
}
Jim Hunziker
  • 14,111
  • 8
  • 58
  • 64
  • It is hard to adjust granularity here. You picked 3 milliseconds here, but maybe that is not the right value for my application. So, this is not an universal solution. – avernus Mar 30 '22 at 14:57