asio在handle级上提供了多线程保护锁,命名为asio::strand,strand(绳、线之一股, 线, 绳, 串, 海滨, 河岸)顾名思义序列化,这个命名可能和asio的工作原理有关.asio的内部维护了一个队列,当异步请求的状态转移为完成时,service会调用对应的线程对应的handle.如果在多线程方式下,可能有多个handle访问共享变量.而strand把这一handle针对这一变量的的操作序列为不可分割的一段,这样另外一段针对这一变量的的操作就必须等该操作完成后才能开始.这样就起到了互斥信号的作用.
详见下面的例子:
#include
#include
#include
#include
#include
class printer
{
public:
printer(boost::asio::io_service& io)
: strand_(io),
timer1_(io, boost::posix_time::seconds(1)),
timer2_(io, boost::posix_time::seconds(1)),
count_(0)
{
timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this)));
timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this)));
}
~printer()
{
std::cout << "Final count is " << count_ << "\n";
}
void print1()
{
if (count_ < 10)
{
std::cout << "Timer 1: " << count_ << "\n";
++count_;
timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(1));
timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this)));
}
}
void print2()
{
if (count_ < 10)
{
std::cout << "Timer 2: " << count_ << "\n";
++count_;
timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(1));
timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this)));
}
}
private:
boost::asio::strand strand_;
boost::asio::deadline_timer timer1_;
boost::asio::deadline_timer timer2_;
int count_;
};
int main()
{
//启动两个线程
//asio的每个线程必须调用io_service::run,这个有点类似com的coinitlize
boost::asio::io_service io;
printer p(io);
boost::thread t(boost::bind(&boost::asio::io_service::run, &io));
io.run();
t.join();
return 0;
}
这个例子的最大不同就是
timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this)));
这一行.我们知道
timer1_.async_wait(boost::bind(&printer::print1, this));
启动了一个时钟请求,而print1和print2函数访问了共享变量cout_,而要互斥地访问该变量,我们只需要用strand把该这两个handle包装一下(wrap).这样一来两个线程就可以安全的在屏幕输出各自的信息(当然,这样一来,输出的信息时间的严格性就无法保证).如果去掉该wrap,我们将看到屏幕的输出是无序的,而且变量的值也会出现变小的现象.
asio的strand当然可以用在自己的函数内部,同时它也是跨平台的互斥量噢.