1、通过post任务给io_service的任务队列,这个队列是线程安全的,所以io_service的run函数可以在多个线程中跑,run函数的本质就是从队列中取出任务进行执行,post到队列和从队列中get出来都是线程安全的;
2、io_service将socket读写提交给IOCP(Proactor)或者epoll(Reactor),提交任务的同时也提交任务完成后要执行的回调,IOCP或epoll在任务完成后会将此回调再post给io_service;
3、整个服务器架构就是每个IO线程有一个io_service(通过Proactor代理),用于处理读写和定时事件;固定数量的IO线程组成一个线程组,为每个socket连接分配一个IO线程,使线程组上的每个线程负载均衡;
4、io_service的好处是,本身可以作为线程池来进行计算,然后又可以将IO读写和定时事件提交给IOCP或者epoll来处理,epoll虽然是Reactor模式的,但io_service提交给它后也是异步返回的,并不会阻塞;
5、非阻塞IO的本质其实是将消息的处理与等待消息的到达进行分离,等待消息的过程必须是阻塞的(比如一个等待读的操作),可以让1个线程为所有连接等待,当文件描述符准备好了(比如TCP的读缓冲区中读入了数据)就通知处理消息的线程进行处理;
6、Reactor和Proactor的区别就是前者多了一层从内核拷贝数据到应用层的阻塞,而io_service通过代理的方式将这层阻塞从处理消息的线程中移出了;
7、C++11并发编程,使用条件变量condition和notify_one(notify_all)可以实现生产者消费者模式,notify对应于V操作,通知condition对应的P操作检查条件变量设定的条件(非线程栈上的对象);
8、C++11的thread如果未执行完就结束生命周期,会调用std::terminate,因为这里C++不能简单地撤销线程,线程持有的资源必须自己去释放,而也不能将这个线程分离出去,因为这个线程可能用到了当前域中的局部对象,而该对象已经被析构了。所以最好的方法是使用RAII来包装裸线程,在析构时调用join;
9、子线程中一旦抛出异常,也会调用std::terminate,使用std::async()可以捕获future.get()中抛出的异常,也可以通过promise的set_exception将异常传递给future来让主线程进行捕获;
10、std::packaged_task将包装的函数的返回值与std::future进行共享,直到两个对象都析构了这个共享对象才会析构;
11、lambada表达式是通过仿函数的类来实现的,如果lambada通过值传递捕获了一个智能指针,那么这个仿函数对象的内部就有一个智能指针的拷贝,这也是lambada表达式的强大之处。当将lambada表达式作为一个函数对象进行传递时,它具备传递所捕获对象的能力,而且这个函数对象的类型可以非常简单比如function