#Boost io_service# 网络编程与IO操作的boost框架
“ 文章所涉及内容更多来自网络,在此声明,并感谢知识的贡献者!”
io_service 是什么—
io_service 简介
io_service对象是asio框架中的调度器,所有异步io事件都是通过它来分发处理的
io_service的作用: io_servie实现了一个任务队列,这里的任务就是void(void)的函数。Io_servie最常用的两个接口是post和run,post向任务队列中投递任务,run是执行队列中的任务,直到全部执行完毕,并且run可以被N个线程调用。Io_service是完全线程安全的队列。
1 post用于发布io事件,如timer,socket读写等,一般由asio框架相应对象调用,无需我们显式调用。
2 run用于监听io事件响应,并执行响应回调,对于异步io操作需要在代码中显式调用,对于同步io操作则由io
对象隐式调用(并不是run函数,不过也是等待io事件)
Io_service 是什么
asio是boost提供的一个c++异步编程模型库,其核心类io_service,在多线程编程里面提供了任务队列和任务分发功能
—
Io_service 用在哪
在socket、io编程里主要作为一个事件驱动器(完成端口、select、poll、epoll等)
—
Io_service 怎么用
每个io_service都一个公有任务队列,和多个私有任务队列,公有队列由各个线程共享,私有队列则是每个线程独享一个。
—
io_service的任务执行流程大致如下:
1调用run方法,进入主loop;
2判断公有队列是否为空,不为空则取出任务并执行,当任务数大于1时同时唤醒其他空闲线程;
3任务执行结束,把各个线程的私有队里面的任务移动到公有任务队列里面;
4触发reactor,linux下面一般是epoll,当有事件时,把相应的事件的任务放到私有队列里。
5当队列为空时,把当前线程加到空闲线程队列里面,同时进入wait状态,等待其他线程的唤醒(task_operation)。
6当用户调用post时,任务是直接投递到公有队列op_queue里面。
—
io_service与线程的模式
1 一个io_service实例和一个处理线程的单线程
当几个处理程序需要被同时调用时,你通常会遇到瓶颈。如果一个处理程序需要花费很长的时间来执行,所有随后的处理程序都不得不等待。
2 一个io_service实例和多个处理线程的多线程
如果几个处理程序被同时调用了,它们会在各自的线程里面被调用。唯一的瓶颈就是所有的处理线程都很忙的同时又有新的处理程序被调用。然而,这是有快速的解决方式的,增加处理线程的数目即可。
3 多个io_service实例和多个处理线程的多线程
当你有成千上万实时(socket)连接时。你可以认为每一个处理线程(运行io_service::run()的线程)有它自己的select/epoll循环;它等待任意一个socket连接,然后等待一个读写操作,当它发现这种操作时,就执行。
—
Io_service 线程池
1多个线程共享一个任务队列
用户把任务投递到该任务队列中,其他线程竞争从该队列中获取任务执行。结合boost::thread,在多个线程里面调用run方法,即可实现该线程池:
using namespace boost;
using namespace boost::asio;
io_service ios;
int thread_num = 10;
thread *t[thread_num] = {0};
// 创建线程池
for(int i = 0; i < thread_num; ++i)
{
t[i] = new thread(bind(&io_service::run, &ios));
}
// 向任务队列中投递任务,该任务将随机由一个调用run方法的线程执行
ios.post(func);
// 等待线程退出
for(int i = 0; i < thread_num; ++i)
{
t[i]->join();
}
问题:
多个线程竞争取任务,在大并发的程序里面容易导致性能下降
2 每个线程各自维护一个任务队列
用户可以选择随机或者轮训地投递任务到其中一个任务队列里面,该任务队列中的任务只由其所在的线程才能消费。这种线程池在boost的example里面也有相应的实现(io_service_pool),基本方法是创建多个io_service对象,每个对应一个thread
using namespace boost;
using namespace boost::asio;
int thread_num = 10;
io_service ios[thread_num];
thread *t[thread_num] = {0};
// 创建线程池
for(int i = 0; i < thread_num; ++i)
{
t[i] = new thread(bind(&io_service::run, &ios[i]));
}
// 轮训投递任务
for(int i = 0; i < thread_num; ++i)
{
ios[i].post(func);
}
// 等待线程退出
for(int i = 0; i < thread_num; ++i)
{
t[i]->join();
}
—
Io_service的机制
io_service定义了主要的接口,在linux下的实现是task_io_service。
task_io_service主要定义了三个东西:
一个reactor,reactor就是完成端口、select、poll、epoll之类的事件驱动器;
一个公共的任务队列op_queue,用来存放用户post的任务,和reactor返回的任务;
线程相关变量。io_service本身不会创建任何线程,但它会保存一些线程调用信息,如线程私有队列等。
此外,task_io_service还维护了一个空闲线程列表,在有多余任务到来时,唤醒其中一个空闲线程。在常见的linux单任务队列的线程池里面,用一个condition变量来唤醒线程,在多核系统里面,一次pthread_cond_signal调用,会唤起处于wait状态的一个或多个线程(参考 https://linux.die.net/man/3/pthread_cond_signal ),尽管只有一个任务,如果采用空闲线程的方法,有任务时只唤醒一个空闲线程,可以减少很多不必要唤醒。
thread_info_base类维护了一个简单的内存池,只有一块内存,仅在连续的申请释放内存情况下,可以减少内存开辟的开销。
—
同步模式
在asio框架中,同步的io主要流程如下:
1 应用程序调用IO对象成员函数执行IO操作
2 IO对象向io_service 提出请求.
3 io_service 调用操作系统的功能执行连接操作.
4 操作系统向io_service 返回执行结果.
5 io_service将错误的操作结果翻译为boost::system::error_code类型,再传递给IO对象.
6 如果操作失败,IO对象抛出boost::system::system_error类型的异常.
异步模式
异步IO的处理流程则有些不同:
1 应用程序调用IO对象成员函数执行IO操作
2 IO对象请求io_service的服务
3 io_service 通知操作系统其需要开始一个异步连接.
4 操作系统指示连接操作完成, io_service从队列中获取操作结果
5 应用程序必须调用io_service::run()以便于接收结果
6 调用io_service::run()后,io_service返回一个操作结果,并将其翻译为error_code,传递到事件回调函数中
—
Io_service 常用方法
io_servie::Post方法
Post向队列中投递任务,然后激活空闲线程执行任务。
io_servie::run方法
Run方法执行队列中的所有任务,直到任务执行完毕。
Run方法的原则是:
- 有任务立即执行任务,尽量使所有的线程一起执行任务
- 若没有任务,阻塞在epoll_wait上等待io事件
- 若有新任务到来,并且没有空闲线程,那么先中断epoll_wait,先执行任务
- 若队列中有任务,并且也需要epoll_wait监听事件,那么非阻塞调用epoll_wait(timeout字段设置为0),待任务执行完毕在阻塞在epoll_wait上。
- 几乎对线程的使用上达到了极致。
- 从这个函数中可以知道,在使用ASIO时,io_servie应该尽量多,这样可以使其epoll_wait占用的时间片最多,这样可以最大限度的响应IO事件,降低响应时延。但是每个io_servie::run占用一个线程,所以io_servie最佳应该和CPU的核数相同。
io_servie::stop方法
停止所有线程的任务
—
io_service的注意问题
1 run函数在io事件完成后会退出,导致后续基于该对象的异步io任务无法执行
给其【io_service】分配一个线程,然后执行run函数。但run函数在io事件完成后会退出,线程会终止,后续基于该对象【io_service】的异步io任务无法得到调度。
通过一个asio::io_service::work对象来守护io_service。这样,即使所有io任务都执行完成,也不会退出,继续等待新的io任务。
boost::asio::io_service io;
boost::asio::io_service::work work(io);
io.run();
2. 回调在run函数的线程中同步执行,当回调处理时间较长时阻塞后续io响应
解决这个问题的方法有两种:
1. 启动多线程执行run函数(run函数是线程安全的)
2. 新启动一个线程(或通过线程池)来执行回调函数。一般来讲,如果回调处理事件不是特别短,应该使用在线程池中处理回调的方式。
3. 回调在run函数的线程中同步执行,io事件较多的时候得不到及时响应
这个其实是性能问题了,在多核cpu上可以通过在多个线程中执行run函数来解决这一问题。这种方式也只能充分利用cpu性能,本身性能问题就不是光靠软件就能解决的。
—
学习范例:
io_service 的使用框架
#include <boost/asio.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/thread.hpp>
#include <boost/atomic.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/date_time.hpp>
#include <iostream>
int main()
{
//io_service asio框架的调度器,在多线程机制中提供任务队列和任务分发功能
boost::asio::io_service io_service;
//work对象来守护io_service,即使所有io任务都执行完成,也不会退出,继续等待新的io任务。
boost::asio::io_service::work work(io_service);
//run用于监听io事件响应,并执行响应回调,1在io事件完成后退出 2io_service调用stop()后退出
io_service.run();
return 0;
}
锁的机制
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>
long num = 0;
//mutex 互斥量
std::mutex num_mutex;
void numplus() {
std::cout << "++ :" << num << std::endl;
//创建互斥量管理对象时,它试图给给定mutex加锁。当程序离开互斥量管理对象的作用域时,互斥量管理对象会析构并且并释放mutex。所以我们则不需要担心程序跳出或产生异常引发的死锁了。
std::lock_guard<std::mutex> lock_guard(num_mutex);
std::cout <<"++ before:" << num << std::endl;
for (long i = 0; i < 1000000; ++i) {
num++;
}
std::cout << num << std::endl;
std::cout << "++ after:" << num << std::endl;
};
void numsub() {
std::cout << "-- :" << num << std::endl;
std::lock_guard<std::mutex> lock_guard(num_mutex);
std::cout << "-- before:" << num << std::endl;
for (long i = 0; i < 1000000; ++i) {
num--;
}
std::cout << "-- after:" << num << std::endl;
}
int main() {
std::thread t1(numplus);
std::thread t2(numsub);
t1.join();
t2.join();
std::cout << num << std::endl;
system("PAUSE");
}
线程池管理
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>
void Run(int nVal)
{
//
int nTemp = nVal * nVal;
//下面输出需要加锁,不能多个线程共享输出。
static boost::mutex mutexCout;
boost::lock_guard<boost::mutex> autoLock(mutexCout);
std::cout << "thread Run: [" << nVal << "] " << nTemp << std::endl;
}
int main(int argc, char * argv[])
{
//定义一个线程组对象。提供了多个线程创建、保存、退出等管理。
boost::thread_group threadGroup;
//设置最大的线程个数。一般来说是CPU的个数的两倍是最高效率的线程模型。
const int nMaxCount = 5;
//循环地创建N个线程。
for (int i = 0; i < nMaxCount; ++i)
{
//使用create_thread函数可以创建多个线程,每个线程都调用函数Run运行。
threadGroup.create_thread(boost::bind(Run, i));
}
//等所有线程退出。使用join_all函数来确保所有线程运行,都从线程运行函数里退出来,如果其中一个线程没有办法退出,那么就会一直等待的。
threadGroup.join_all();
system("PAUSE");
return 0;
}
多线程中使用io_service 使得线程一直运行
#include <boost/asio/io_service.hpp>
#include <boost/thread/thread.hpp>
#include <iostream>
//asio 任务调度器
boost::asio::io_service io_service;
void WorkerThread()
{
std::cout << "Thread Start\n";
//在多个线程中调用run()即可开启线程池,io_service负责执行任务处理。阻塞在线程里
io_service.run();
std::cout << "Thread Finish\n";
}
int main(int argc, char * argv[])
{
//work类型的指针
boost::shared_ptr< boost::asio::io_service::work > work(new boost::asio::io_service::work(io_service));
//输出信息
std::cout << "Press [return] to exit." << std::endl;
//创建线程池/线程组
boost::thread_group worker_threads;
for (int x = 0; x < 4; ++x)
{
//创建线程
worker_threads.create_thread(WorkerThread);
}
//主线程获取监听输入
std::cin.get();
//stop()会告知io_service,所有的任务需要终止。它的调用可能会使已经进入队列的任务得不到执行。
io_service.stop();
//等所有线程退出。使用join_all函数来确保所有线程运行,都从线程运行函数里退出来,如果其中一个线程没有办法退出,那么就会一直等待的。
worker_threads.join_all();
//屏幕暂停关闭
system("PAUSE");
return 0;
}
Bind的使用
#include <boost/asio/io_service.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <iostream>
//互斥量
boost::mutex global_stream_lock;
void WorkerThread(boost::shared_ptr< boost::asio::io_service > io_service)
{
//线程id
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id() << "] Thread Start" << std::endl;
global_stream_lock.unlock();
//io_service阻塞
io_service->run();
//
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id() << "] Thread Finish" << std::endl;
global_stream_lock.unlock();
}
int main(int argc, char * argv[])
{
//智能指针,维护对象,进行自动管理
boost::shared_ptr< boost::asio::io_service > io_service(new boost::asio::io_service);
boost::shared_ptr< boost::asio::io_service::work > work(new boost::asio::io_service::work(*io_service));
//主线程 id
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id() << "] Press [return] to exit." << std::endl;
global_stream_lock.unlock();
//多线程
boost::thread_group worker_threads;
for (int x = 0; x < 4; ++x)
{
//使用boost::bind可以把函数调用包装成为对象。便于传递参数
worker_threads.create_thread(boost::bind(&WorkerThread, io_service));
}
//主线程获取键盘数据
std::cin.get();
//io_service关闭任务
io_service->stop();
//等所有线程退出。使用join_all函数来确保所有线程运行,都从线程运行函数里退出来,如果其中一个线程没有办法退出,那么就会一直等待的。
worker_threads.join_all();
//屏幕暂停关闭
system("PAUSE");
return 0;
}
Post dispatch
#include <boost/asio/io_service.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <iostream>
boost::mutex global_stream_lock;
void WorkerThread(boost::shared_ptr< boost::asio::io_service > io_service,int i)
{
std::cout << i << std::endl;
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id() << "] Thread Start" << std::endl;
global_stream_lock.unlock();
io_service->run();
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id() << "] Thread Finish" << std::endl;
global_stream_lock.unlock();
}
//dispatch会立即执行任务,否则把任务加入到queue
void Dispatch(int x)
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id() << "] " << __FUNCTION__ << " x = " << x << std::endl;
global_stream_lock.unlock();
}
//post只会把任务加入到队列
void Post(int x)
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id() << "] " << __FUNCTION__ << " x = " << x << std::endl;
global_stream_lock.unlock();
}
void Run3(boost::shared_ptr< boost::asio::io_service > io_service)
{
for (int x = 0; x < 3; ++x)
{
io_service->dispatch(boost::bind(&Dispatch, x * 2));
io_service->post(boost::bind(&Post, x * 2 + 1));
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
}
}
int main(int argc, char * argv[])
{
boost::shared_ptr< boost::asio::io_service > io_service(new boost::asio::io_service);
boost::shared_ptr< boost::asio::io_service::work > work(new boost::asio::io_service::work(*io_service));
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id() << "] The program will exit when all work has finished." << std::endl;
global_stream_lock.unlock();
boost::thread_group worker_threads;
for (int x = 0; x < 1; ++x)
{
worker_threads.create_thread(boost::bind(&WorkerThread, io_service, x));
}
io_service->post(boost::bind(&Run3, io_service));
//立即结束任务
work.reset();
worker_threads.join_all();
//屏幕暂停关闭
system("PAUSE");
return 0;
}
Strand 顺序处理
#include <boost/asio/io_service.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <boost/asio/strand.hpp>
#include <iostream>
boost::mutex global_stream_lock;
void WorkerThread(boost::shared_ptr< boost::asio::io_service > io_service)
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id() << "] Thread Start" << std::endl;
global_stream_lock.unlock();
io_service->run();
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id() << "] Thread Finish" << std::endl;
global_stream_lock.unlock();
}
void PrintNum(int x)
{
std::cout << "[" << boost::this_thread::get_id() << "] x: " << x << std::endl;
}
int main(int argc, char * argv[])
{
boost::shared_ptr< boost::asio::io_service > io_service(new boost::asio::io_service);
boost::shared_ptr< boost::asio::io_service::work > work(new boost::asio::io_service::work(*io_service));
//strand提供顺序化的事件执行器。意思是,如果以“work1->work2->work3”的顺序post,不管有多少个工作线程,它们依然会以这样的顺序执行任务。
boost::asio::io_service::strand strand(*io_service);
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id() << "] The program will exit when all work has finished." << std::endl;
global_stream_lock.unlock();
boost::thread_group worker_threads;
for (int x = 0; x < 2; ++x)
{
worker_threads.create_thread(boost::bind(&WorkerThread, io_service));
}
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
//strand.post( boost::bind( &PrintNum, 1 ) );
//strand.post( boost::bind( &PrintNum, 2 ) );
//strand.post( boost::bind( &PrintNum, 3 ) );
//strand.post( boost::bind( &PrintNum, 4 ) );
//strand.post( boost::bind( &PrintNum, 5 ) );
io_service->post(boost::bind(&PrintNum, 1));
io_service->post(boost::bind(&PrintNum, 2));
io_service->post(boost::bind(&PrintNum, 3));
io_service->post(boost::bind(&PrintNum, 4));
io_service->post(boost::bind(&PrintNum, 5));
work.reset();
worker_threads.join_all();
return 0;
}
boost::noncopyable
#include <iostream>
#include <boost/noncopyable.hpp>
class Test1 {
public:
Test1(int i) { std::cout << "This is Test1 that is copyable" << std::endl; }
};
//将私有化类的拷贝构造函数和拷贝赋值操作符,这样子类可以调用,但是外部调用者不能通过复制/赋值等语句来产生一个新的对象。不支持使用复制的方式来实例化类。
class Test2 : boost::noncopyable {
public:
Test2(int i) { std::cout << "This is Test2 that is noncopyable" << std::endl; }
};
int main()
{
Test1 t1(1);
Test2 t2(2);
Test1 t3 = t1; // It's OK
Test1 t4(t1); // It's OK
Test2 t5 = t2; // Cannot be referenced
Test2 t6(t2); // Cannot be referenced
Test2 &t7 = t2; // It's OK
return 0;
}
boost::asio::deadline_timer 计时器 同步模式
#include <iostream>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
int main()
{
//创建任务调度器 io_service
boost::asio::io_service io;
//定时器
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
//阻塞等待,boost::asio::deadline_timer::wait()的在创建后5秒内(注意:不是等待开始后),timer到时之前不会返回任何值.
t.wait();
//boost::asio::deadline_timer::wait()在到时的timer对象上调用,会立即return,输出信息
std::cout << "Hello, world! ";
return 0;
}
boost::asio::deadline_timer 计时器 异步模式
#include <iostream>
#include <boost/asio.hpp>
void handler(const boost::system::error_code &ec)
{
std::cout << "5 s." << std::endl;
}
int main()
{
boost::asio::io_service io_service;
boost::asio::io_service::work work(io_service);
boost::asio::deadline_timer timer(io_service, boost::posix_time::seconds(5));
timer.async_wait(handler);
std::cout << "soon." << std::endl;
io_service.run();
}
多线程执行任务:一个io_service多个thread
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <iostream>
void handler1(const boost::system::error_code &ec)
{
for (int i = 0; i < 10000; i++)
{
std::cout << "1." << std::endl;
}
}
void handler2(const boost::system::error_code &ec)
{
for (int i = 0; i < 10000; i++)
{
std::cout << "2." << std::endl;
}
}
boost::asio::io_service io_service;
void run()
{
io_service.run();
}
int main()
{
boost::asio::deadline_timer timer1(io_service, boost::posix_time::seconds(5));
timer1.async_wait(handler1);
boost::asio::deadline_timer timer2(io_service, boost::posix_time::seconds(5));
timer2.async_wait(handler2);
boost::thread thread1(run);
boost::thread thread2(run);
thread1.join();
thread2.join();
}
在 main() 中创建了两个线程。这两个线程均针对同一个 I/O 服务调用了 run() 方法。这样当异步操作完成时,这个 I/O 服务就可以使用两个线程去执行句柄函数。
两个计时数均被设为在五秒后触发。由于有两个线程,所以 handler1() 和 handler2() 可以同时执行。如果第二个计时器触发时第一个仍在执行,则第二个句柄就会在第二个线程中执行。如果第一个计时器的句柄已经终止,则 I/O 服务可以自由选择任一线程。
线程可以提高应用程序的性能。因为线程是在处理器内核上执行的,所以创建比内核数更多的线程是没有意义的。这样可以确保每个线程在其自己的内核上执行,而没有同一内核上的其它线程与之竞争。
多个io_service多个thread
多次调用同一个 I/O 服务的 run()方法,是为基于 Boost.Asio 的应用程序增加可扩展性的推荐方法。另外还有一个不同的方法:不要绑定多个线程到单个 I/O 服务,而是创建多个 I/O 服务。然后每一个 I/O 服务使用一个线程。如果 I/O 服务的数量与系统的处理器内核数量相匹配,则异步操作都可以在各自的内核上执行。
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <iostream>
void handler1(const boost::system::error_code &ec)
{
for (int i = 0; i < 10000; i++)
{
std::cout << "1." << std::endl;
}
}
void handler2(const boost::system::error_code &ec)
{
for (int i = 0; i < 10000; i++)
{
std::cout << "2." << std::endl;
}
}
boost::asio::io_service io_service1;
boost::asio::io_service io_service2;
void run1()
{
io_service1.run();
}
void run2()
{
io_service2.run();
}
int main()
{
boost::asio::deadline_timer timer1(io_service1, boost::posix_time::seconds(5));
timer1.async_wait(handler1);
boost::asio::deadline_timer timer2(io_service2, boost::posix_time::seconds(5));
timer2.async_wait(handler2);
boost::thread thread1(run1);
boost::thread thread2(run2);
thread1.join();
thread2.join();
}
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <iostream>
using namespace boost::asio;
io_service service;
void func(int i) {
std::cout << "func called, i= " << i << std::endl;
}
void worker_thread() {
service.run();
}
int main(int argc, char* argv[]) {
for (int i = 0; i < 10; ++i)
service.post(boost::bind(func, i));
boost::thread_group threads;
for (int i = 0; i < 3; ++i)
threads.create_thread(worker_thread);
// wait for all threads to be created
boost::this_thread::sleep(boost::posix_time::millisec(500));
threads.join_all();
getchar();
}
循环计时器
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
void print(const boost::system::error_code& /*e*/,
boost::asio::deadline_timer* t, int* count)
{
if (*count < 5)
{
std::cout << *count << std::endl;
}
++(*count);
std::cout << *count << std::endl;
//在计时器处理程序中调用deadline_timer :: expires_from_now和deadline_timer :: async_wait来执行此操作,这将在最后一个计时器到期时添加计时器
t->expires_at(t->expires_at() + boost::posix_time::seconds(5));
t->async_wait(boost::bind(print,
boost::asio::placeholders::error, t, count));
}
int main()
{
boost::asio::io_service io;
int count = 0;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
t.async_wait(boost::bind(print,
boost::asio::placeholders::error, &t, &count));
io.run();
std::cout << "Final count is " << count << std::endl;
return 0;
}
—
参考资料
https://www.cnblogs.com/fnlingnzb-learner/p/10402232.html
https://blog.csdn.net/qq_38365116/article/details/85102103
https://blog.csdn.net/guotianqing/article/details/100730340
boost::thread_group join_all
https://blog.csdn.net/caimouse/article/details/8741295
互斥量、锁
https://www.cnblogs.com/flyinggod/p/13570390.html
io_service 多线程,一个线程绑定一个函数
https://blog.csdn.net/guotianqing/article/details/100730340
boost::noncopyable
https://blog.csdn.net/rangfei/article/details/122464346
boost::asio::io_service post run stop reset work
https://www.cnblogs.com/fnlingnzb-learner/p/10402232.html
io_service 与多线程的模式
https://blog.csdn.net/qq_38365116/article/details/85102103
boost::asio::io_service创建线程池简单实例
https://blog.csdn.net/guotianqing/article/details/100730340
boost::asio 网络编程
https://blog.csdn.net/smilejiasmile/article/details/114330843
boost asio 重复计时器
https://www.icode9.com/content-4-494864.html
boost 多线程使用
https://blog.csdn.net/alppkk4545/article/details/101575899
https://www.cnblogs.com/ttmoon/p/7658224.html
https://www.codenong.com/22826143/
https://www.codenong.com/61276549/
https://blog.csdn.net/zzhongcy/article/details/85162856
std thread join 等待线程执行返回
https://blog.csdn.net/duan19920101/article/details/121357347
智能指针reset()方法分析
https://blog.csdn.net/qq43645149/article/details/130037999
reset()函数接受一个可选参数,这个参数可以是一个指向新对象的指针,也可以是一个空指针。
当参数为空指针时,reset()会释放原来指针所管理的资源,同时将指针置为空。当参数为非空指针时,
reset()会先释放原来指针所管理的资源,然后将指针重新指向新对象,
此时此刻,如果有其它智能指针也指向它,只是计数减一。
当使用reset函数时,智能指针的引用计数会相应地减少1。如果减少后引用计数变为0,则表示该资源不再被使用,可以安全地删除资源。
Io_service 线程池
https://blog.csdn.net/hlday6/article/details/82696916