c++11 - 运行相同 io_service 的两个线程
问题描述
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;
}
每次我运行这个示例时,输出看起来都不错,因为:
两个定时器同时启动
两个定时器同时过期(5s后异步)
同时调用回调(3s 后)
作者说,这段代码有比赛,不应该工作(车库输出)。
不太清楚的是我们有两个线程,每个线程可以服务一个完成处理程序(这里是计时器回调)。那么为什么要比赛呢?事实上,我多次运行此代码并且无法产生作者提出的任何垃圾输出。
输出看起来符合预期,这是一个示例:
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
解决方案
处理程序在io_service::run
. 您启动了两个io.run()
有效的线程。所以你同时有两个运行方法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
对象访问不会导致崩溃(根据参考),
多线程对同步 ([ios.members.static]) 标准 iostream 对象的格式化和未格式化输入和输出函数或标准 C 流的并发访问不应导致数据竞争。[ 注意:如果用户希望避免交错字符,则仍必须同步多个线程对这些对象和流的并发使用。
但是为了避免这些交错的字符,您必须在访问时添加同步cout
,例如通过使用std::mutex
,或以串行方式调用处理程序 - 使用 boost.js 中的strand
对象。
推荐阅读
- javascript - Pagespeed Insights 页面得分使用 Adsense 下降
- javascript - 为什么我的 Javascript 幻灯片无法正常工作
- string - Golang 追加和删除字符的优化方法是什么
- c - C中的函数问题(可读性)
- css - 通过 CSS 类将自定义字体添加到引导类行?
- docker - 启动 Docker VPN 容器会杀死其他容器中的互联网
- reactjs - 带有反应 js 的样式化组件
- python - 在相当简单的 GUI 中调用 tkraise() 时出现网格布局问题
- html - 将 box-shadow 应用于 Bootstrap 4 卡片组件
- python - 仅包含 2 个输入列表之间共有元素的列表(如果没有重复,我无法做到)