I am trying to scale a boost single threaded application to a multi threaded application. The code is based on this article . The approach I am taking is to have dedicated IO_Context for each thread. In my application I need to post ASIO JOB from other thread to the other thread's IO_Context. As per boost article this should work but my application is crashing with segmentation fault after few iterations.
#include <boost/asio.hpp>
#include <iostream>
#include <iomanip>
namespace asio = boost::asio;
using namespace std::chrono_literals;
using boost::system::error_code;
static std::atomic_int tid_gen = 0;
thread_local int const tid = [] { return ++tid_gen; }();
static constexpr auto now = std::chrono::steady_clock::now;
static auto const start = now();
static std::mutex console_mx;
void trace(auto const&... msg) {
std::lock_guard lk(console_mx);
std::cerr << "at " << std::setw(8) << (now() - start)/1ms << "ms - tid:" << tid << " ";
(std::cerr << ... << msg) << std::endl;
}
void worker(asio::io_context& ioContext) {
trace("Worker thread enter");
ioContext.run(); // Run the io_context to handle asynchronous operations
trace("Worker thread exit");
}
int main() {
try {
asio::io_context ioContext1;
asio::io_context ioContext2;
std::function<void(const boost::system::error_code& error)> handler1;
std::function<void(const boost::system::error_code& error)> handler2;
asio::steady_timer task1(ioContext1, 100ms);
asio::steady_timer task2(ioContext2, 200ms);
handler1 = [&task1, &handler1, &ioContext2](error_code ec) {
//trace("Start Task1: ", ec.message());
if (!ec)
usleep(5000);
asio::post(ioContext2, []{
trace("Task1 posted job on Task2");
});
task1.async_wait(handler1);
};
task1.async_wait(handler1);
handler2 = [&task2, &handler2, &ioContext1](error_code ec) {
//trace("Start Task2: ", ec.message());
if (!ec)
usleep(10000);
asio::post(ioContext1, []{
trace("Task2 posted job on Task1");
});
task2.async_wait(handler2);
};
task2.async_wait(handler2);
// Create a work object to prevent ioContext.run() from returning immediately
auto work1 = make_work_guard(ioContext1);
auto work2 = make_work_guard(ioContext2);
// Create multiple worker threads
std::vector<std::thread> threads;
threads.emplace_back(worker, std::ref(ioContext1));
threads.emplace_back(worker, std::ref(ioContext2));
trace("App started :", std::thread::hardware_concurrency());
work1.reset();
work2.reset();
// Join the worker threads
for (auto& thread : threads) {
thread.join();
}
trace("All worker threads joined.");
} catch (std::exception const& e) {
trace("Exception: ", std::quoted(e.what()));
}
}
Here is the back trace
Thread 3 "application" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x763de380 (LWP 29973)]
boost::asio::detail::scheduler::do_run_one (this=this@entry=0x42d188, lock=..., this_thread=..., ec=...) at /usr/include/boost/asio/detail/impl/scheduler.ipp:458
Is this approach should work or expected to fail? I have tried adding separate locks before posting the jobs but that also did not help.
My application is running on linux with boost library version 1.79
I am trying to scale a boost single threaded application to a multi threaded application. The code is based on this article . The approach I am taking is to have dedicated IO_Context for each thread. In my application I need to post ASIO JOB from other thread to the other thread's IO_Context. As per boost article this should work but my application is crashing with segmentation fault after few iterations.
Here is the back trace
Is this approach should work or expected to fail? I have tried adding separate locks before posting the jobs but that also did not help. My application is running on linux with boost library version 1.79