该并发服务器框架模仿 陈硕的Muduo库来实现,采用reactor + threadpool的模式,是一个能适应密集计算的并发服务器框架。该项目主要分为两个部分:reactor+ threadpool。reactor负责将TCP连接进行封装,并采用Event-Loop模式结合epoll多路复用进行监听,然后注册相应的回调函数,并且将IO线程与计算线程分离。threadpool部分基于Posix线程实现,会依次对互斥锁,条件变量,任务队列,线程,线程池类进行封装,同时注册相应的回调函数。
该项目主要分为两个部分,reactor + threadpool。
- reactor网络库部分
reactor部分主要将TCP网络编程中的socket,bind,listen,accpet与SocketIO等操作进行封装,并且使用Event-Loop模式结合多路复用epoll进行监听描述符,之后再为reactor注册相关的回调函数。 回调函数有三个:
-
新连接产生时的回调函数;
-
连接发来消息时的回调函数;
-
连接终止时的回调函数。
在进行完以上操作之后reactor就可以监听端口,处理新连接,处理对端发来的消息,处理连接断开的情况。
注意:
-
第二个回调函数会将消息封装成任务添加到线程池中的任务队列,这也是reactor 与 threadpool之间的桥梁。
-
计算线程不能够直接给客户端发送消息,所以需要将计算线程与IO线程进行分离(设置
eventfd
)。
- threadpool线程池部分
线程池的部分主要对Posix线程
进行了封装,对多线程以下五个部分进行了封装:
-
mutex互斥锁的加解锁封装,并且利用对象的生命周期实现自动加解锁,以防忘记解锁之类的;
-
条件变量condition的封装,实现线程间的同步。
-
任务队列的封装,将线程间的同步与互斥都隐藏在任务队列的入队和出队中,并且设置好任务的安全退出机制,确保所有的线程在退出时都能够被安全的
join
。 -
线程类的封装,采用基于对象线程类的设计,通过注册回调函数的方式实现线程类的功能。
-
线程池类的封装,将任务队列与多个线程封装在一起,许多个线程争抢并执行任务队列中的任务。
建议依次从Version1.0
开始学习,一直学习到 Version5.0
,每一个版本都会在原版本上新增更多内容。依次递进的学习,更有利于掌握该并发服务器模型。之后再去学习陈硕老师的muduo库
,便是更加得心应手。
- 搭建线程池框架
技术亮点:基于对象线程池设计
,Posix线程同步与互斥
,任务队列
,自动加解锁类
,线程安全退出机制
,bind回调函数
, 智能指针unique_ptr
- 搭建服务器框架
技术亮点:基于对象服务器设计
,bind回调函数
,socket网络编程
,TCP连接
,IO多路复用epoll
,eventfd(IO线程与计算线程分离)
,客户端安全退出机制
,智能指针shared_ptr
- pthread_cond_wait如何使用?
- 必须先pthread_mutex_lock进行加锁,线程进入锁池
- 进入pthread_cond_wait之后,将该线程加入内核的等待队列之后,释放锁,线程重新进入锁池
- 等待pthread_cond_signal唤醒之后,内核会给线程加锁,也就是线程在锁池中获得锁;
- 此时一般进行while条件判断: 1):情况满足则 执行execute语句之后再pthread_mutex_unlock解锁 2):情况不满足则 再次重复执行pthread_cond_wait
用代码的体现形式就是:
while (1){
pthread_mutex_lock(&mutex);
while (condition){
pthread_cond_wait(&cond,&mutex);
}
//execute work
...
pthread_mutex_unlock(&mutex);
}
- pthread_cond_signal 和 pthread_cond_broadcast的区别?
实质上这个问题和Java中的 notify 和 notifyAll的问题有相似之处。
pthread_cond_signal: 是唤醒通过 pthread_cond_wait 进入等待队列中的某一个线程,再次进入锁池争抢锁。
pthread_cond_broadcast: 是唤醒通过 pthread_cond_wait 进入等待队列中的所有线程,再次进入锁池争抢锁。