c++ - Is running new thread in Timer.5 boost::asio tutorial necessary?
问题描述
Question 1: Is starting a new thread in Timer.5 boost::asio tutorial really needed?
...
boost::thread t(boost::bind(&boost::asio::io_context::run, &io));
io.run();
t.join();
...
Tutorial says:
As you already know, the asio library provides a guarantee that callback handlers will only be called from threads that are currently calling io_context::run().
But if I run this
...
// boost::thread t(boost::bind(&boost::asio::io_context::run, &io));
io.run();
// t.join();
...
... callbacks are still executed despite the fact that timers are started asynchronously.
Also I may have understood this tutorial in wrong way, I am new at boost::asio but it looks to me that this tutor doesn't depict what author wanted to demonstrate.
Author says:
The single threaded approach is usually the best place to start when developing applications using asio. The downside is the limitations it places on programs, particularly servers, including:
- Poor responsiveness when handlers can take a long time to complete.
- An inability to scale on multiprocessor systems.
So when author tells about poor responsiveness it means that we could run multiple tasks (callbacks in this case) concurrently so that we engage all available cores.
But this approach works ideally when there are no shared data to modify.
However in this tutorial callbacks DO modify shared variable count
and write to cout
.
To avoid concurrent modification author places callbacks into strand
object which guarantees that callbacks execute one after another in order they came into the "queue".
So callbacks are not something heavy and long-to-execute in this tutorial ...
Question 2: Do you think that using strand
object is necessary in this tutorial?
I think this tutorial is overengineered, once again please correct me if I am wrong, but this code without additional thread and strand
object seems to work the same way as original tutorial:
#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
class printer
{
public:
printer(boost::asio::io_context& io)
: timer1_(io, boost::asio::chrono::seconds(1)),
timer2_(io, boost::asio::chrono::seconds(1)),
count_(0)
{
timer1_.async_wait(boost::bind(&printer::print1, this));
timer2_.async_wait(boost::bind(&printer::print2, this));
}
~printer()
{
std::cout << "Final count is " << count_ << std::endl;
}
void print1()
{
if (count_ < 10)
{
std::cout << "Timer 1: " << count_ << std::endl;
++count_;
timer1_.expires_at(timer1_.expiry() + boost::asio::chrono::seconds(1));
timer1_.async_wait(boost::bind(&printer::print1, this));
}
}
void print2()
{
if (count_ < 10)
{
std::cout << "Timer 2: " << count_ << std::endl;
++count_;
timer2_.expires_at(timer2_.expiry() + boost::asio::chrono::seconds(1));
timer2_.async_wait(boost::bind(&printer::print2, this));
}
}
private:
boost::asio::steady_timer timer1_;
boost::asio::steady_timer timer2_;
int count_;
};
int main()
{
boost::asio::io_context io;
printer p(io);
io.run();
return 0;
}
Question 3: Is the code above correct?
Thanks in advance.
解决方案
从第二个线程调用run()
a 是本教程的重点。
你的两个问题有相同的答案。Timer.5 教程向您展示了如何让超过 1 个线程服务io_context
(超过 1 个线程调用run()
)。但是运行多线程意味着您必须保护共享状态免受并发访问,这就是strand
需要对象的原因。
run()
你是对的,在这个例子中,如果你只从一个线程调用,你就不需要 strand 。
推荐阅读
- javascript - 使用 jQuery/javascript,如何正确解析 HTML 表格以将要更新的每一行的内容发送到数据库中
- ios - iOS 证书固定和亚马逊证书管理器
- listview - SwiftUI 使用 CoreData 从列表中编辑项目
- ios - 在 Xcode 中保护 API 密钥的最佳/最简单方法是什么?
- r - 为什么我的闪亮应用程序不起作用?' 没有名为 'tidyverse' 的包'
- sql-server - SQL Server 插入:使用静态值确定日期值
- ruby-on-rails - Rails - 一个来自多个模型,没有父级
- c++ - 方法的冲突类型
- numpy - 交叉验证并获得每个类别标签的精确度、召回率和 F 分数
- command-line - 给定 rust 中的绝对路径,如何上传文件?