Skip to main content

Posting inside a boost asio strand serialized(strand) vs unserialized(strand.get_inner_executor())

· 2 min read
Hreniuc Cristian-Alexandru

We had an issue in our server, there were some dataraces. After an investigation we've detected that when we were posting inside a strand, we were using the get_inner_executor() method from the strand, and this resulted in posting the handler to the io_context that was used when creating the strand, it wasn't used the strand, which meant no serialization.

An example of code can be found below.

// g++ -I/home/chreniuc/.conan/data/boost/1.71.0/cvs/stable/package/7b385070ffa5d0bc45c44f2812dbfda8a3854dbd/include -pthread main.cpp -o test 


#include <iostream>
#include <thread>
#include <chrono>

#include <boost/asio/strand.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/executor_work_guard.hpp>

using namespace ::std;

void printElements()
{
cout << "Begin Thread id " << this_thread::get_id() << endl;
this_thread::sleep_for(std::chrono::seconds(20));
cout << "End Thread id " << this_thread::get_id() << endl;
}

void printElementsSerizlized()
{
cout << "[Serialized] Begin Thread id " << this_thread::get_id() << endl;
this_thread::sleep_for(std::chrono::seconds(20));
cout << "[Serialized] End Thread id " << this_thread::get_id() << endl;
}

int main()
{
boost::asio::io_context io_context;
::boost::asio::strand<::boost::asio::io_context::executor_type>
strand(io_context.get_executor());

// Post inside the io_context, not serialized
::boost::asio::post( strand.get_inner_executor(), printElements);
::boost::asio::post( strand.get_inner_executor(), printElements);
// Post inside the strand, serialized
::boost::asio::post( strand, printElementsSerizlized);
::boost::asio::post( strand, printElementsSerizlized);

thread t1([&]{io_context.run();});
thread t2([&]{io_context.run();});
thread t3([&]{io_context.run();});
thread t4([&]{io_context.run();});

cout << "join main" << endl;

t1.join();
t2.join();
t3.join();
t4.join();
cout << "end main" << endl;

return 0;
}

Output:

⬤ boost_asio_test ♦ ./test 
Begin Thread id [Serialized] Begin Thread id 139912278222592join main

139912261437184
Begin Thread id 139912269829888
End Thread id 139912278222592
[Serialized] End Thread id 139912261437184
[Serialized] Begin Thread id 139912261437184
End Thread id 139912269829888
[Serialized] End Thread id 139912261437184
end main