Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wait for all pending completion handlers to be executed before stopping io_service?

I'm writing a server using boost::asio. I have multiple threads each owning it's own io_service object. I'm using io_service::work object to keep io_service running when there is no completion handlers to execute. In certain moment I'm calling stop method of io_service objects to finish threads which called io_serice::run. But in some cases when I'm calling stop I have posted in io_service object competion handlers which are not finished. Calling stop prevents posted competion handlers from executing, but this is unacceptable for me because I need all pending work to be finished before stopping the thread. How to wait for all pending completion handlers first to be executed before calling stop method of io_service?

like image 642
bobeff Avatar asked Oct 14 '16 15:10

bobeff


1 Answers

Just reset the work.

Any io_service::run() will return when all pending work has been completed.

The common pattern is to use optional<work> so you can clear it. If it is a frequent thing, you could reduce some mental overhead by wrapping it in a RAII-enabled class:

Live On Coliru

#include <boost/asio.hpp>
#include <boost/optional.hpp>

struct work {
    using io_service = boost::asio::io_service;
    work(io_service& svc) : _work(io_service::work(svc)) 
    { }

    void release() {
        _work.reset();
    }

    void enlist(io_service& svc) {
        _work.emplace(io_service::work(svc));
    }

  private:
    boost::optional<io_service::work> _work;
};

#include <thread>
#include <iostream>
using namespace std::chrono_literals;

int main() {
    boost::asio::io_service svc;
    work lock(svc);

    std::thread background([&] { svc.run(); });

    std::this_thread::sleep_for(1s);

    std::cout << "releasing work";
    lock.release();

    background.join();
}

Which finishes the background thread after 1 second.

like image 72
sehe Avatar answered Nov 11 '22 01:11

sehe