Home > Software design >  Boost-Asio io_context post after run
Boost-Asio io_context post after run

Time:03-07

I am new to Boost::asio and I am currently looking at io_context. In the docs https://www.boost.org/doc/libs/1_75_0/doc/html/boost_asio/reference/io_context.html shown is the following example:

{
  ...
}

...

boost::asio::io_context io_context;

// Submit a function to the io_context.
boost::asio::post(io_context, my_task);

// Submit a lambda object to the io_context.
boost::asio::post(io_context,
    []()
    {
      ...
    });

// Run the io_context until it runs out of work.
io_context.run();

However, I would like to be able to post even after io_context.run() has been called. Essentially, something like this:

#include <boost/asio.hpp>

int value = -1;

void my_task()
{
  value = 42;
}

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

  // Submit a function to the io_context.
  //boost::asio::post(io_context, my_task);

  // Run the io_context until it runs out of work.
  io_context.run();

  boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work(io_context.get_executor());

  // Submit a lambda object to the io_context.
  boost::asio::post(io_context,
      []()
      {
        my_task();
      });

  assert(value == 42);

}

After compiling the above with g -o a example.cpp -lboost_system -lpthread I am getting an assertion failure. What is the "right" way to accomplish this?

CodePudding user response:

io_context::run() blocks as long as there is work to do. In your first example, you could just wait until both the posted tasks are finished. After that, io_context::run() returns and you can submit new work and call run() again. If you don't want this sequential behavior but rather submit tasks while the io_context works on tasks, you need a second thread, that executes io_conext::run(). You can create one for example like this:

#include <thread>

//...

std::thread my_thread( [&](){ io_context.run(); } );

// post more work here

// wait for it to finish
my_thread.join();

Make sure that the io_context object lives longer than the thread, if you use the lamda capture by reference like in this example.

CodePudding user response:

Either run the io_context on a separate thread, or, indeed use the execution context that already has that built in.

Using a manual thread

Live On Coliru

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

int value = -1;

void my_task() { value = 42; }

int main() {
    boost::asio::io_context io_context;
    auto work = make_work_guard(io_context);

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

    // submit to the io_context
    post(io_context, my_task);

    work.reset();
    thread.join();

    std::cout << value << "\n";
}

Prints

g   -std=c  20 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
42

Using asio::thread_pool:

Live On Coliru

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

int value = -1;

void my_task() { value = 42; }

int main() {
    boost::asio::thread_pool io(1);

    post(io, my_task);

    io.join();

    std::cout << value << "\n";
}

As you can see it's basically the same, but

  • Related