网络模型的选择
当多个任务到来时需要对其进行及时响应,并将任务下发给特定的处理线程,完成对应的任务。如果只用传统的服务器模型:同步阻塞、单线程进行listen轮询监听的话,那效率和并发往往达不到需求。而我们借助 epoll 的话就会很完美的解决这个问题
关于epoll请阅读:Linux下的I/O复用与epoll详解
常用的网络IO模型 :五种网络IO模型
ThreadPool
当实现高并发服务器时,当然需要实现多线程并发工作来处理多个客户端的连接。那么方法有如下
方案:
-
每当客户端发送一个请求,服务器创建一个线程来处理客户端的连接请求。
-
先预先创建若干个线程,并让线程先阻塞。每当一个请求到来唤醒一个线程,对其进行处理,处理完毕后继续阻塞。
对比:
- 是动态创建,当一个任务到达,就需要创建线程,当任务处理完毕后对线程进行销毁。
- 而是先预先创建,线程处理完任务后无需销毁,可以继续阻塞等待下一个任务。
很明显方案1的开销会远大于方案2.从这一点来看需要选择方案2。
但是1也有优点。那就是他可以动态创建,保证每个任务在内核承载能力允许的情况下,可以及时处理。所以怎么样才可以将二者的优点结合呢?
那就是在方案2的基础上再创建一个线程,一直轮询监听任务数,来动态增加或者删减任务数。这样也就是线程池。
实现
生产者消费者模型
详细介绍和实现可参考:生产者与消费者问题C语言实现
首先,我们是利用生产者消费者模型来实现这个服务器模型。谁来充当消费者和生产者的模型呢,下面介绍一下生产者和消费者在本模块的大致功能。
生产者功能:
- 对客户端的连接请求进行监听。
- 将客户端的连接请求存储到一个容器中。
- 当任务不为空时发送不为空信号来通知消费者来接收。
消费者功能:
- 监听生产者发送的不为空信号。
- 当收到信号时,从容器取走任务并对其处理。
- 向生产者发送容器未满信号。(因为任务如果过快的话容器可能已经放满,生产者无法接着接受客户端请求)
所以,由上可得
生产者就是epoll模型,消费者就是线程池。
线程池
1.线程池(一个结构体)。
既然是线程池,首先需要一个标识符来表明这个线程池是否已经开始使用或者是否已经被关闭。其次我们需要一个记录每个线程的tid的数组,和存放管理线程的id的mtid变量,来方便管理线程对普通i线程的回收。那么就需要以下结构体成员:
int thread_shutdown

276

被折叠的 条评论
为什么被折叠?



