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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With