Asio官方文档 的非官方中文翻译 (Tutorial-0-4)

这篇教程介绍了如何在多线程程序中使用strand类模板同步执行回调函数,以解决单线程限制问题。通过创建一个包含两个计时器的printer类,并利用strand确保回调函数不会同时执行,从而实现对共享资源如std::cout和count_的同步访问。在多线程环境中,回调操作访问共享资源时应确保同步,这里通过在每个回调函数中绑定到相同的strand来实现这一目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自己翻译的 没有任何参考价值

Timer.5 - Synchronising handlers in multithreaded programs
https://www.boost.org/doc/libs/1_74_0/doc/html/boost_asio/tutorial/tuttimer5.html


Timer.5 - Synchronising handlers in multithreaded programs

这次的教程会演示在一个多线程程序中用strand类模板来同步执行回调函数.

前面的四篇教程中,我们通过使用单线程上的io_context::run()函数,避免了多线程同步的问题.如你所知,asio库保证回调函数都只会在io_context::run()的执行线程上被执行.也就是说,如果我们只在一个线程上执行io_context::run(),那就意味着各个回调函数不可能并行执行.

以单线程方式来入门asio编程是一个不错的选择.但是单线程也有它的的缺点: 它对程序,特别是服务器上的程序存在限制,这些限制包括:

  • 存在耗时操作时.系统的实时响应能力差.
  • 在多处理器系统上不能扩展.

如果你苦于这些限制的话,通常的解决方式是去搞一池子线程来执行io_context::run().这样就能实现回调函数的并行处理了.然而,这也使得它们能够同时访问线程不安全的共享数据.因此我们需要一种手段来进行同步.

#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind/bind.hpp>

首先跟之前一样,定义一个printer类.不过这次在原先的基础改成了两个并行的计时器.

class printer
{
public:

构造函数里除了初始化两个boost::asio::steady_timer成员之外,还初始化了一个叫strand_的成员,这是一个boost::asio::strand< boost::asio::io_context::executor_type >类型的对象.

strand类模板是一种executor adapter(可能翻译成执行者适配器?),它能够保证由他经手的回调函数不会同时执行.当然了,不由同一个strand调度的各个回调函数还是可以并行执行的.

	printer(boost::asio::io_context& io)
		: strand_(boost::asio::make_strand(io)),
		  timer1_(io, boost::asio::chrono::seconds(1)),
		  timer2_(io, boost::asio::chrono::seconds(1)),
		  count_(0)
  	{

初始化这些异步操作的时候,每一个回调函数都绑到了一个boost::asio::strand< boost::asio::io_context::executor_type >的类对象上.函数boost::asio::bind_executor()返回的是一个新的回调函数, 这个回调函数已经自动由strand负责调度了.这么一来,这两个函数绑到了同一个strand上面,我们就能确保他们不会被同时执行了.

		timer1_.async_wait(boost::asio::bind_executor(strand_,
			boost::bind(&printer::print1, this)));
		timer2_.async_wait(boost::asio::bind_executor(strand_,
			boost::bind(&printer::print2, this)));
	}
	~printer()
	{
		std::cout << "Final count is " << count_ << std::endl;
	}

在一个多线程程序中,如果回调处理操作访问了共享资源,那他们的异步操作应该是受同步的.本教程中,print1跟print2访问的共享资源是std::cout和成员变量count_.

	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::asio::bind_executor(strand_,
				boost::bind(&printer1, 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::asio::bind_executor(strand_,
				boost::bind(&printer::print2, this)));
		}
	}

private:
	boost::asio::strand<boost::asio::io_context::executor_type> strand_;
	boost::asio::steady_timer timer1_;
	boost::asio::steady_timer timer2_;
	int count_;
};

这次的main函数要在两个线程分别调用io_context::run(): 主线程调用一次,再申请一个线程再调一个.这将用boost::thread类对象来完成.

和之前单线程的时候一样,多线程上的io_context::run()也会等手头"活儿"干完之后再停止.后台线程在所有异步操作执行结束之前不会退出.

int main()
{
	boost::asio::io_context io;
	printer p(io);
	boost::thread t(boost::bind(&boost::asio::io_context::run, &io));
	io.run();
	t.join();

	return 0;
}

再回顾一下整体的代码(发现好像stl里没有bind_executor的替代品)

#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind/bind.hpp>

class printer
{
public:
	printer(boost::asio::io_context& io)
		: strand_(boost::asio::make_strand(io)),
		  timer1_(io, boost::asio::chrono::seconds(1)),
		  count_(0)
  	{
  		timer1_.async_wait(boost::asio::bind_executor(strand_,
  			boost::bind(&printer::print1, this)));
		timer2_.async_wait(boost::asio::bind_executor(strand_,
			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::asio::bind_executor(strand_,
				boost::bind(&printer::printer1, 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::asio::bind_executor(strand_,
				boost::bind(&printer::print2, this)));
		}
	}

private:
	boost::asio::strand<boost::asio::io_context::executor_type> strand_;
	boost::asio::steady_timer timer1;
	boost::asio::steady_timer timer2;
	int count_;
};

int main()
{
	boost::asio::io_context io;
	printer p(io);
	boost::thread t(boost::bind(&boost::asio::io_context::run, &io));
	io.run();
	t.join();
	
	return 0;
}

Timer.5 - Synchronising handlers in multithreaded programs
https://www.boost.org/doc/libs/1_74_0/doc/html/boost_asio/tutorial/tuttimer5.html

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值