Johannes Gerer
Johannes Gerer

Reputation: 25818

Is boost::io_service::post thread safe?

Is it thread safe to post new handlers from within a handler? I.e. Can threads that called the io_service::run() post new Handlers to the same io_service?

Thanks

Upvotes: 12

Views: 7515

Answers (2)

Fabio
Fabio

Reputation: 1

Note by me, who edited this post heavily: The original code had a few subtile bugs, so that it seemed to disproof thread-safety of ASIO. I have marked the corrections necessary to get the correct counter of 3000000 after execution. Look at the edit history to see the code changes made. The most important update is to change service.stop(), which keeps some of the posted work undone, to guard.reset(), which allows the io_service to exit, once all work has been completed.

I choose to edit instead of post a different answer, as most of the code is still from the original author. As the later was only active many, many years ago and comments about his bugs had been made long time ago, it wouldn't have made sense to wait longer.

#include <boost/asio/io_service.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/thread.hpp>
#include <boost/thread/detail/thread_group.hpp>
#include <memory>
#include <iostream>

void postInc(boost::asio::io_service *service, std::atomic_int *counter) {
  for(int i = 0; i < 100000; i++) service->post([counter] { (*counter)++; });
}

int main(int argc, char **argv)
{
  std::atomic_int counter(0);
  
  {
    boost::asio::io_service service;
    // boost::asio::io_service::work working(service);
    auto guard = make_work_guard(service);
    boost::thread_group workers;
    
    for(size_t i = 0; i < 10;++i)     workers.create_thread(boost::bind(&boost::asio::io_service::run, &service));

    boost::thread_group producers;
    for (int it = 0; it < 30; it++)
    {
      producers.add_thread(new boost::thread(boost::bind(postInc,&service,&counter)));
    }

    producers.join_all();
    std::cout << "producers ended" << std::endl;

    // service.stop();
    guard.reset();
    workers.join_all();
  }

  std::cout << counter.load() << std::endl;

  return 0;
}

Upvotes: 0

Sam Miller
Sam Miller

Reputation: 24164

It is safe to post handlers from within a handler for a single instance of an io_service according to the documentation.

Thread Safety

Distinct objects: Safe.

Shared objects: Safe, with the exception that calling reset() while there are unfinished run(), run_one(), poll() or poll_one() calls results in undefined behaviour.

Upvotes: 10

Related Questions