稍微进阶点的搞实验中的杂谈(一)—— 主要关于boost asio例程2,多个io_service的server,例程3,多个线程一个io_service
在看第二个例程,额,第一个例程也花得够多时间的,不过我觉得还是值得,毕竟把基本的框架都搭建了起来,就差个多线程了,还自己写了很多补充的方法,定义了我要用到的请问的报文格式,嗯嗯,今天杭州天气不错的。
这个server2的例程的话,其实改动不大,它的标题是one io_service per cpu,其实大部分的源文件还是跟server1的一样的,主要就是用一个叫 io_service_pool的类代替了原本的connection_manager,这个类就是用来管理一堆Io_service的,主要核心的变量我暂时一眼看出应该就是这三个吧:
private: typedef boost::shared_ptr<boost::asio::io_service> io_service_ptr; typedef boost::shared_ptr<boost::asio::io_service::work> work_ptr; /// The pool of io_services. std::vector<io_service_ptr> io_services_; /// The work that keeps the io_services running. std::vector<work_ptr> work_; /// The next io_service to use for a connection. std::size_t next_io_service_;
然后相应地,server类也要做一点点改动,总之就是,外部负责与客户端打交道的逻辑稍微改变下,因为要处理多个io_service也就是要多个Connection,但是内部处理request啊怎样handle read和wirte的,还是没变的
然后这个work的作用我特意查了下,这个朋友说得简单明了的,大概理解了:http://www.cnblogs.com/hurricane2011/articles/2384437.html
让io保持繁忙,呵呵,不让退出,除非io.stop()执行。
然后server端其实就是每次接到i请求的话,就会一个线程来应答这个请求,而这个线程其实是事先生成好的,每个线程负责在跑着一个ioservice:
void io_service_pool::run() { // Create a pool of threads to run all of the io_services. std::vector<boost::shared_ptr<boost::thread> > threads; for (std::size_t i = 0; i < io_services_.size(); ++i) { boost::shared_ptr<boost::thread> thread(new boost::thread( boost::bind(&boost::asio::io_service::run, io_services_[i]))); threads.push_back(thread); } // Wait for all threads in the pool to exit. for (std::size_t i = 0; i < threads.size(); ++i) threads[i]->join(); }
而在io_service_pool对象构造函数执行的时候,已经有了一堆的io_service(用智能指针去指向它),每个指针都被work来搞得在忙了:
io_service_pool::io_service_pool(std::size_t pool_size) : next_io_service_(0) { if (pool_size == 0) throw std::runtime_error("io_service_pool size is 0"); // Give all the io_services work to do so that their run() functions will not // exit until they are explicitly stopped. for (std::size_t i = 0; i < pool_size; ++i) { io_service_ptr io_service(new boost::asio::io_service); work_ptr work(new boost::asio::io_service::work(*io_service)); io_services_.push_back(io_service); work_.push_back(work); } }
那个next_io_service就是一个普通的int用来实现最简单的round robin,每次就加+1,用来指派下一个线程,从get_io_service方法中搞的。
ok了,其他没什么特别的,总的来说再啰嗦一次,就是有一个类维护了一个vector的ioservice和实现了一个计数器,用来每次取出不同的ioservice来应答server端发过来的请求,不过貌似挺占内存的…不知道呢,进入到真正多现场的server3例程吧!
然后看了下例程三,貌似也什么太多新意的地方…只是这次它是在server类里面,维护了一个vector<boost::shared_ptr<boost::thread>> threads,然后对比起,例程2的server::run,例程2直接调用了io_service_pool的run,启动多个线程然后每个线程分别运营着一个io_service,而例程三就直接是这样:
void server::run() { // Create a pool of threads to run all of the io_services. std::vector<boost::shared_ptr<boost::thread> > threads; for (std::size_t i = 0; i < thread_pool_size_; ++i) { boost::shared_ptr<boost::thread> thread(new boost::thread( boost::bind(&boost::asio::io_service::run, &io_service_))); threads.push_back(thread); } // Wait for all threads in the pool to exit. for (std::size_t i = 0; i < threads.size(); ++i) threads[i]->join(); }
这个io_service依然是server类制剂的私有变量,然后值得一提的是在connnection类里面,多了这个:
/// Strand to ensure the connection's handlers are not called concurrently. boost::asio::io_service::strand strand_;
这个如果没记错的话就是boost里面用来保证线程之间的安全的,反正在connection的方法里面,凡是有asyncread或者write的话,都要用strand把bind方法来wrap一下,就比如这样:
if (result) { request_handler_.handle_request(request_, reply_); boost::asio::async_write(socket_, reply_.to_buffers(), strand_.wrap( boost::bind(&connection::handle_write, shared_from_this(), boost::asio::placeholders::error))); }
然后看了其他的类,都没什么变化了,唯一区别就在这里了,看来这篇可以这么完结了,接下来好好想想怎样想想写好服务端的多线程框架然后测试下吧,两台机子这样。