This tutorial demostrates the use of the boost::asio::strand class to synchronies callback handlers in a multithreaded program .
该教程演示了如何将 boost::asio::strand 类应用于多线程编程中的同步化回调句柄中
The previous four tutorials avoided the issu of handler synchronisation by calling the io_service::run() function from one thread only .
前面的四个教程代码中避免了 通过调用 io_service::run() 方法来实现的句柄同步化仅仅适用于单线程环境中.
As you already know , the asio library provides a guarantee that callback handlers will only be called from threads that are currently calling io_service::run().
正如你所知, asio 函数库会保证这一点: 只有调用 io_service::run() 方法的线程才能够调用回调函数.
Consequently, calling io_service::run() from only one thread ensures that callback handlers can not run concurrently .
这样一来,io_service::run() 方法仅能够被一个线程实体所调用,这样便确保了回调函数无法并发的执行.
The single threaded approach is usually the best place to start when developing application using asio .
当使用 asio 库来开发应用程序的时,最好从单线程这一角度来着手解决问题.
The downside is the limitations it places on programs, particularly server, including :
(单线程解决问题的方法)的缺陷便是它对基于其思想开发出来的特别是服务器方向所开发出的程序,有了极大的限制,这些限制有:
Poor reponsiveness when handlers can take a long time to complete.
当句柄对应调用的函数需要很长一段时间才能够运行结束的话,该服务器程序的响应性将会变得极差.
An inability to scale on multiprocessor systems.
(以单线程思想编写出的程序)无法运行在多处理系统中 .
If you find yourself running into these limitations, an alternative approach is to have a pool of threads calling io_service::run () .
如果你觉得自己已经深陷这些限制中,一个灵活的解决方法就是通过创建一个线程池的线程来调用 io_service::run() 这个方法.
However , as this allows handlers to execute concurrently , we need a method of synchronisation when handlers might be accessing a shared, thread-unsafe resource.
虽然这样做(创建线程池),可以通过调用句柄来实现程序的并发运行,但是当多个句柄同时访问同一个非线程安全的共享资源的时,我们便需要设计一套同步机制出来.
-
#include <iostream>
-
#include <boost/asio.hpp>
-
#include <boost/thread/thread.hpp>
-
#include <boost/bind.hpp>
-
#include <boost/date_time/posix_time/posix_time.hpp>
We start by defining a class called printer, similar to the class in the previous tutorial by running two timers in parallel.
首先,我们来定义一个名为 printer 的类,和前面几节教程代码中所定义的类相仿,我们在这个类中创建两个可以并列运行的计时器
In addition to initialising a pair of boost::asio::deadline_timer members, the constructor initialises the strand_ member , an object of type boost::asio::strand .
除了要在构造函数中初始化这对 boost::asio::deadline_timer 成员变量以外,还要初始化 boost::asio::strand 的类实例 strand_ 成员对象才可以.
An boost::asio::strand guarantees that , for thoese handlers that are dispatched through it , and executing handler will be allowed to complete before the next one is started.
boost::asio::strand 可以确保,通过调用 strand 中的方法而分离的多个句柄,正在运行绑定方法的句柄会直到运行结束之后才会允许下一个句柄执行其绑定的方法。
/boost::asio::strand 中提供分离线程的方法,通过该strand 所分离出的线程中的句柄方法,从运行开始便不会被其余线程中的句柄方法打断,
/ 直至其运行结束之后,才允许下一个线程中的句柄绑定的方法运行
This is gurarnteed irrespective of the number of threads that are calling io_service::run().
/ strand 中提供的这个保证可以无需考虑调用 io_service::run() 方法的线程数目
Of course, the handlers may still execute concurrently with other handlers that were not dispatched through an boost::asio::strand,
or were disptached through a different boost::asio::strand object.
当然,句柄也可以同没有调用 boost::asio::strand 方法分离的线程 ,或是通过调用其他 boost::asio::strand 实例对象而分离的线程并发执行
-
printer(boost::asio::io_service &io )
-
:strand_(io),
-
timer1_(io, boost::posix_time::seconds(1)),
-
timer2_(io, boost::posix_time::seconds(1)),
-
count_(0)
-
{
When initiating the asynchronous operations, each callback handler is "wrapped" using the boost::asio::strand object.
当启动异步操作的时候,每个回调函数句柄都被 boost::asio::strand 对象所 "封装" 了.
The strand::wrap() function returns a new handler that automatically dispatches its contained handler through the boost::asio::strand object.
strand::wrap() 方法将会返回一个新的句柄对象,这个句柄对象将会通过调用 boost::asio::strand 对象中的方法来自动地将其所包含的回调函数句柄对象分离出来.
By wrapping the handlers using the same boost::asio::strand, we are ensure that they cannot execute concurrently.
被相同的一个 boost::asio::strand 对象实例封装的回调函数句柄对象之间,我们可以确保它们是无法并发执行的.
/ 也就是说,如果我们不想让 fun1 fun2 fun3 三个方法并发执行的话,将其三个通过同一个 boost::asio::strand 对象实例进行"封装"
/ 那么这三个方法是无法实现并行的,这种解决问题的思想应该是,通过 并发中的局部串行化 来避免使用加锁、互斥访问临界资源
/ 或者可以这样想,通过同一个 strand 封装的多个对象而言,运行的时候有着严格的顺序性
-
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 " << cout_ << std::endl ;
-
}
In a multithreaded program , the handlers for asynchronous operations should be synchronised if they access shared resources. In this tutorial, the shared resources
used by the handlers(print1 and print2) are std::cout and the count_ data member .
在多线程编程中,如果异步操作中的句柄函数涉及到访问共享资源的话,应该遵照一定的同步机制执行才可以。在本教程中,共享资源是会被(print1, print2) 两个回调句柄函数
都会执行的通过执行 std::cout 将成员变量 count_ 数值的输出操作.
-
void print1()
-
{
-
if ( count_ < 10 )
-
{
-
std::cout << "Timer 1 : " << count_ << std::endl ;
-
++count_ ;
-
-
timer1_.expires_at(timer1_.expires_at() +
-
boost::posix_time::seconds(1) ) ;
-
-
timer1_.async_wait( strand_.wrap(boost::bind(&printer::printer1, this ))) ;
-
}
-
}
-
-
void print2()
-
{
-
if ( count_ < 10 )
-
{
-
std::cout << "Timer 2 :"<< count_ << std::endl ;
-
++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::io_service::strand strand_ ;
-
boost::asio::deadline_timer timer1_ ;
-
boost::asio::deadline_timer timer2_ ;
-
-
int count_ ;
-
}
The main function now causes io_service::run() to be called from two threads :the main thread and one additional thread.
main 这一主方法中将会涉及到两个线程,主线程和另一个线程,来调用 io_service::run() 方法的操作了
This is accomplished using an boost::thread object.
另一个线程的创建通过调用 boost::thread 来创建的实体来实现.
Just as it would with a call from a single thread, concurrent calls to io_service::run () will continue to execute while there is "work" left to do .
就像是在单线程环境下面一样,来自多线程并发调用会让 io_service::run() 方法持续的运行,只要还有"工作要做的话" .
The background thread will not exit until all asynchronous operations have completed.
后台进程将会持续运行直到所有的异步操作均完成之后才会退出.
-
int main ()
-
{
-
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 ;
-
}
阅读(1498) | 评论(0) | 转发(0) |