Is boost::io_service::post thread safe?
Asked Answered
R

2

12

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

Rodmun answered 16/6, 2011 at 8:50 Comment(0)
I
10

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.

Icing answered 16/6, 2011 at 15:50 Comment(0)
D
0

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;
}
Disadvantage answered 2/6, 2014 at 20:21 Comment(2)
You shouldn't stop the service. It stops way before workers finished to work.Migrant
You should have stopped the service upon joining workersShastashastra

© 2022 - 2024 — McMap. All rights reserved.