https://youtu.be/rwOv_tw2eA4?t=1030
此示例具有一个io_service和两个正在运行的线程。
io_service附加了两个任务:timer1和timer2
创建了两个线程来运行io_service
void timer_expired( std:: string id )
{
std::cout << timestamp() << ": " << id << ": begin\n";
std::this_thread::sleep_for( std::chrono::seconds(3) );
std::cout << timestamp() << ": " << id << ": end\n";
}
int main()
{
boost::asio::io_service io_service;
boost::asio::deadline_timer timer1( io_service, boost::posix_time::seconds(5) );
boost::asio::deadline_timer timer2( io_service, boost::posix_time::seconds(5) );
timer1.async_wait( []( auto ... ){ timer_expired("timer1"); });
timer2.async_wait( []( auto ... ){ timer_expired("timer2"); });
std::cout << timestamp() << ": calling io_service run\n";
std::thread thread1( [&](){ io_service.run(); } );
std::thread thread2( [&](){ io_service.run(); } );
thread1.join();
thread2.join();
std::cout << timestamp() << ": done\n";
return 0;
}
每次运行此示例时,输出看起来都不错,因为:
两个计时器同时启动
两个计时器同时到期(5秒后,它们是异步的)
回调是在同一时间(3秒后)被调用的
作者指出,此代码中存在种族,应该不起作用(车库输出)。
不太清楚的是,我们有两个线程,每个线程可以服务一个完成处理程序(此处为计时器回调)。那为什么要比赛呢?而且我多次运行此代码,并且无法像作者所介绍的那样产生任何垃圾输出。
输出看起来像预期的一样,这是一个示例:
2019-07-28 11:27:44: calling io_service run
2019-07-28 11:27:49: timer1: begin
2019-07-28 11:27:49: timer2: begin
2019-07-28 11:27:52: timer1: end
2019-07-28 11:27:52: timer2: end
2019-07-28 11:27:52: done
答案 0 :(得分:1)
处理程序在io_service::run
中调用。您在io.run()
工作的地方启动了两个线程。因此,您同时拥有两个runnig方法timer_expired
。比赛是在访问cout
流的同时进行的。
您很幸运看到如此出色的输出,但是当您在timer_expired
中添加更多作品时:
void timer_expired( std:: string id )
{
std::cout << timestamp() << ": " << id << ": begin\n";
std::this_thread::sleep_for( std::chrono::seconds(3) );
// ADD MORE LINES TO BE PRINTED
for (int i = 0; i < 1000; ++i)
std::cout << timestamp() << ": " << id << ": end" << std::endl;
}
您将看到交错的字符。
许多线程cout
对象的访问不会导致崩溃(根据reference),
并发访问同步([ios.members.static])标准 iostream对象的格式化和未格式化输入和输出功能 或多线程的标准C流不应导致数据 种族。 [注意:用户仍必须同步同时使用这些 如果它们希望避免多个线程的对象和流 交错字符。
但是要避免这些交错的字符,您必须在访问cout
时添加同步,例如通过使用std::mutex
或以串行方式调用处理程序-使用boost中的strand
对象。