设计时要区分:面向多消息的多线程还是面向多连接的多线程。

一、服务器线程模型分类

(1)循环模式:只能同时监听一个事件源,来一个连接生成一个线程。这只能是多线程,不能算线程池,需要和controler/worker配合使用。这种模型当客户端连接数快速增长是就会出现性能瓶颈。因为创建线程需要浪费大量的时间。

(2)反应模式(reactor):通过多路复用select,可以同时监听多个事件源。这也只能是多线程,不能算线程池,需要和controler/worker配合使用

(3)Controler/Workers(适合多消息的处理):主控线程预先生成很多线程,并负责事件源,及worker线程的启动和同步。当到来一个连接时,启动一个阻塞队列中的工作线程负责处理该连接。在linux中可以通过条件变量来实现。可能出现的性能问题:controler把工作交给一个worker线程的时候可能需要上下文切换,包括数据拷贝。

(4)Leader/Followers(LF)(适合多连接的处理):所有的线程都是对等的。该模型所有线程会有三种身份中的一种:leader和follower,以及一个干活中的状态proccesser。它的基本原则就是,永远最多只有一个leader。而所有follower都在等待成为leader。线程池启动时会自动产生一个Leader负责等待网络IO事件,当有一个事件产生时,Leader线程首先通知一个Follower线程将其提拔为新的Leader,然后自己就去干活了,去处理这个网络事件,处理完毕后加入Follower线程等待队列,等待下次成为Leader。该模型的优点是解决了controler/workers不足,Leader-Followers模型可以增强CPU高速缓存相似性,及消除动态内存分配和线程间的数据交换。实现方式:让所有线程去竞争一个mutex,得到的成为leader,负责阻塞连接,当接收到连接时,解除mutex,并负责处理该连接。处理完之后又去竞争mutex,并阻塞。是不是太简单。

线程池的作用:提高消息(任务)响应的实时性、提高任务执行的速度。


二、线程池的注意事项

(1)线程池大小。多线程应用并非线程越多越好,需要根据系统运行的软硬件环境以及应用本身的特点决定线程池的大小。一般来说,如果代码结构合理的话,线程数目与CPU 数量相适合即可。如果线程运行时可能出现阻塞现象,可相应增加池的大小;如有必要可采用自适应算法来动态调整线程池的大小,以提高CPU 的有效利用率和系统的整体性能。

(2)并发错误。多线程应用要特别注意并发错误,要从逻辑上保证程序的正确性,注意避免死锁现象的发生。

(3)线程泄漏。这是线程池应用中一个严重的问题,当任务执行完毕而线程没能返回池中就会发生线程泄漏现象。

三、Controler/Workers线程池模型

        wKioL1XhL3aDi522AAG4i65H-0I129.jpg

一个典型的Controler/Workers线程池,应该包括如下几个部分:

1、线程池管理器(ThreadPool),用于启动、停用,管理线程池

2、工作线程(WorkThread),线程池中的线程

3、请求接口(WorkRequest),创建请求对象,以供工作线程调度任务的执行

4、请求队列(RequestQueue&#