为什么在 asico 教程 Timer.5 示例中我们需要在主线程和新线程 `t` 中 运行 `io.run`?
Why do we need to run `io.run` in both main thread and a new thread `t` within asico tutorial Timer.5 example?
参考:tuttimer5
根据教程,主要函数如下所示:
int main()
{
boost::asio::io_context io;
printer p(io);
boost::thread t(boost::bind(&boost::asio::io_context::run, &io));
io.run(); // Why do we need to call io.run() here?
t.join();
return 0;
}
我想明白为什么我们需要在主函数中有两个io.run();
。
这是我的测试结果:
测试1(在主函数内的主线程中调用io.run()):
main-Thread #32
printer-Thread #32
print1-Thread #32
Timer 1: 0
print2-Thread #32
Timer 2: 1
print1-Thread #32
Timer 1: 2
print2-Thread #32
Timer 2: 3
print1-Thread #32
Timer 1: 4
print2-Thread #32
Timer 2: 5
print1-Thread #32
Timer 1: 6
print2-Thread #32
Timer 2: 7
print1-Thread #32
Timer 1: 8
print2-Thread #32
Timer 2: 9
~printer-Thread #32
Final count is 10
观察 1:print1
和 print2
都被主线程调用。
测试 2(不在主函数内的主线程中调用 io.run()):
main-Thread #40
printer-Thread #40
print1-Thread #29
Timer 1: 0
print2-Thread #29
Timer 2: 1
print1-Thread #29
Timer 1: 2
print2-Thread #29
Timer 2: 3
print1-Thread #29
Timer 1: 4
print2-Thread #29
Timer 2: 5
print1-Thread #29
Timer 1: 6
print2-Thread #29
Timer 2: 7
print1-Thread #29
Timer 1: 8
print2-Thread #29
Timer 2: 9
~printer-Thread #40
Final count is 10
观察 2:print1
和 print2
都没有被主线程调用。
注:测试结果来自我本地的linux盒子(g++ (Ubuntu 11.1.0-1ubuntu1~18.04.1) 11.1.0))。结果看起来和coliru有点不同。
In that case io_context operates like a classic thread pool.
Asynchronous tasks are performed somewhere on the OS side, however
completion handlers are invoked on those threads where io_context::run
function is running. To be more precise: every completion handler is
invoked on a first free thread which io_context::run function is
running on.
问题>我们想在原教程的主线程和新线程中调用io.run);
的主要原因是什么?
谢谢
None 是必需的。它仅表明任务分布在参与 running/polling 执行上下文的所有线程上。
从这个意义上说,所编写的代码只是获得 2 个线程 运行 io 上下文的最便宜的方法。在更新的 Boost 版本中,有人可能会争辩说 thread_pool
是更简洁的代码,但会产生 3 个线程(算上主线程):
int main()
{
report("main") << std::endl;
boost::asio::thread_pool io(2);
printer p(io.get_executor());
io.join();
}
#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <iomanip>
#include <iostream>
#include <thread>
namespace asio = boost::asio;
std::ostream& report(const std::string& suffix_msg)
{
auto tid = std::hash<std::thread::id>{}(std::this_thread::get_id()) % 100;
return std::cout << suffix_msg << "-Thread #" << std::setw(2)
<< std::setfill('0') << tid;
}
class printer {
public:
printer(asio::any_io_executor ex)
: strand_(asio::make_strand(ex))
, count_(0)
{
report("printer") << std::endl;
timer1_.async_wait(
std::bind(&printer::print_callback, this, "Timer 1", std::ref(timer1_)));
timer2_.async_wait(
std::bind(&printer::print_callback, this, "Timer 2", std::ref(timer2_)));
}
~printer()
{
report("~printer") << "\tFinal count is " << count_ << std::endl;
}
void print_callback(std::string_view name, asio::steady_timer& timer)
{
if (count_ < 10) {
report("print_callback") << "\t" << name << ": " << count_ << std::endl;
++count_;
timer.expires_at(timer.expiry() + asio::chrono::seconds(1));
timer.async_wait(std::bind(&printer::print_callback, this, name,
std::ref(timer)));
}
}
private:
asio::any_io_executor strand_;
int count_ = 0;
asio::steady_timer timer1_{strand_, asio::chrono::seconds(1)};
asio::steady_timer timer2_{strand_, asio::chrono::seconds(1)};
};
int main()
{
report("main") << std::endl;
boost::asio::thread_pool io(2);
printer p(io.get_executor());
io.join();
}
打印例如
main-Thread #59
printer-Thread #59
print_callback-Thread #06 Timer 1: 0
print_callback-Thread #06 Timer 2: 1
print_callback-Thread #74 Timer 1: 2
print_callback-Thread #74 Timer 2: 3
print_callback-Thread #74 Timer 1: 4
print_callback-Thread #74 Timer 2: 5
print_callback-Thread #74 Timer 1: 6
print_callback-Thread #74 Timer 2: 7
print_callback-Thread #74 Timer 1: 8
print_callback-Thread #74 Timer 2: 9
~printer-Thread #59 Final count is 10
参考:tuttimer5
根据教程,主要函数如下所示:
int main()
{
boost::asio::io_context io;
printer p(io);
boost::thread t(boost::bind(&boost::asio::io_context::run, &io));
io.run(); // Why do we need to call io.run() here?
t.join();
return 0;
}
我想明白为什么我们需要在主函数中有两个io.run();
。
这是我的测试结果:
测试1(在主函数内的主线程中调用io.run()):
main-Thread #32
printer-Thread #32
print1-Thread #32
Timer 1: 0
print2-Thread #32
Timer 2: 1
print1-Thread #32
Timer 1: 2
print2-Thread #32
Timer 2: 3
print1-Thread #32
Timer 1: 4
print2-Thread #32
Timer 2: 5
print1-Thread #32
Timer 1: 6
print2-Thread #32
Timer 2: 7
print1-Thread #32
Timer 1: 8
print2-Thread #32
Timer 2: 9
~printer-Thread #32
Final count is 10
观察 1:print1
和 print2
都被主线程调用。
测试 2(不在主函数内的主线程中调用 io.run()):
main-Thread #40
printer-Thread #40
print1-Thread #29
Timer 1: 0
print2-Thread #29
Timer 2: 1
print1-Thread #29
Timer 1: 2
print2-Thread #29
Timer 2: 3
print1-Thread #29
Timer 1: 4
print2-Thread #29
Timer 2: 5
print1-Thread #29
Timer 1: 6
print2-Thread #29
Timer 2: 7
print1-Thread #29
Timer 1: 8
print2-Thread #29
Timer 2: 9
~printer-Thread #40
Final count is 10
观察 2:print1
和 print2
都没有被主线程调用。
注:测试结果来自我本地的linux盒子(g++ (Ubuntu 11.1.0-1ubuntu1~18.04.1) 11.1.0))。结果看起来和coliru有点不同。
In that case io_context operates like a classic thread pool. Asynchronous tasks are performed somewhere on the OS side, however completion handlers are invoked on those threads where io_context::run function is running. To be more precise: every completion handler is invoked on a first free thread which io_context::run function is running on.
问题>我们想在原教程的主线程和新线程中调用io.run);
的主要原因是什么?
谢谢
None 是必需的。它仅表明任务分布在参与 running/polling 执行上下文的所有线程上。
从这个意义上说,所编写的代码只是获得 2 个线程 运行 io 上下文的最便宜的方法。在更新的 Boost 版本中,有人可能会争辩说 thread_pool
是更简洁的代码,但会产生 3 个线程(算上主线程):
int main()
{
report("main") << std::endl;
boost::asio::thread_pool io(2);
printer p(io.get_executor());
io.join();
}
#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <iomanip>
#include <iostream>
#include <thread>
namespace asio = boost::asio;
std::ostream& report(const std::string& suffix_msg)
{
auto tid = std::hash<std::thread::id>{}(std::this_thread::get_id()) % 100;
return std::cout << suffix_msg << "-Thread #" << std::setw(2)
<< std::setfill('0') << tid;
}
class printer {
public:
printer(asio::any_io_executor ex)
: strand_(asio::make_strand(ex))
, count_(0)
{
report("printer") << std::endl;
timer1_.async_wait(
std::bind(&printer::print_callback, this, "Timer 1", std::ref(timer1_)));
timer2_.async_wait(
std::bind(&printer::print_callback, this, "Timer 2", std::ref(timer2_)));
}
~printer()
{
report("~printer") << "\tFinal count is " << count_ << std::endl;
}
void print_callback(std::string_view name, asio::steady_timer& timer)
{
if (count_ < 10) {
report("print_callback") << "\t" << name << ": " << count_ << std::endl;
++count_;
timer.expires_at(timer.expiry() + asio::chrono::seconds(1));
timer.async_wait(std::bind(&printer::print_callback, this, name,
std::ref(timer)));
}
}
private:
asio::any_io_executor strand_;
int count_ = 0;
asio::steady_timer timer1_{strand_, asio::chrono::seconds(1)};
asio::steady_timer timer2_{strand_, asio::chrono::seconds(1)};
};
int main()
{
report("main") << std::endl;
boost::asio::thread_pool io(2);
printer p(io.get_executor());
io.join();
}
打印例如
main-Thread #59
printer-Thread #59
print_callback-Thread #06 Timer 1: 0
print_callback-Thread #06 Timer 2: 1
print_callback-Thread #74 Timer 1: 2
print_callback-Thread #74 Timer 2: 3
print_callback-Thread #74 Timer 1: 4
print_callback-Thread #74 Timer 2: 5
print_callback-Thread #74 Timer 1: 6
print_callback-Thread #74 Timer 2: 7
print_callback-Thread #74 Timer 1: 8
print_callback-Thread #74 Timer 2: 9
~printer-Thread #59 Final count is 10