FrozenHeart
FrozenHeart

Reputation: 20746

boost asio and condition variables -- strange output

Suggest that I have the following code:

#include <boost/asio/io_service.hpp>
#include <boost/thread.hpp>

#include <condition_variable>
#include <iostream>
#include <mutex>

const int THREAD_POOL_SIZE = 2;

std::condition_variable g_cv;
std::mutex g_cv_mutex;
bool g_answer_ready;

void foo()
{
  std::cout << "foo \n";
  std::unique_lock<std::mutex> lock(g_cv_mutex);
  g_answer_ready = true;
  g_cv.notify_all();
}

int main()
{
  boost::asio::io_service io_service;

  for (int i = 0; i < 10; ++i)
  {
    std::auto_ptr<boost::asio::io_service::work> work(new boost::asio::io_service::work(io_service));

    boost::thread_group threads;
    for (int i = 0; i < THREAD_POOL_SIZE; ++i)
    {
      threads.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
    }

    std::unique_lock<std::mutex> lock(g_cv_mutex);

    io_service.post(foo);

    g_answer_ready = false;
    g_cv.wait_for(lock, std::chrono::milliseconds(2000));

    if (!g_answer_ready)
    {
      std::cout << "timed_out \n";
    }

    io_service.stop();
    threads.join_all();
  }
}

The output will be different between program's launches. For example,

foo
timed_out
foo
foo

However, if I move boost::asio::io_service object construction inside the loop, it works as expected:

foo
foo
foo
foo
foo
foo
foo
foo
foo
foo

Why? What am I doing wrong? How can I fix it?

boost 1.54, MSVC-11.0

Upvotes: 1

Views: 421

Answers (1)

qehgt
qehgt

Reputation: 2990

If I understand you correctly, you need to fix last lines on your loop (see comments for descriptions):

// io_service.stop();
// threads.join_all();

work.reset(); // <- signal to process all pending jobs and quit from io_service::run function
threads.join_all(); // <- wait for all threads
io_service.reset(); // <- now `io_service` can accept new tasks

So, there were two issues in the original code:

  • io_service.stop() will cancel posted but not yet processed jobs (usually this is not what a programmer wants),
  • io_service.reset() is required to change the state of io_service from "stopped" to "ready to accept new jobs".

Upvotes: 1

Related Questions