服务器开发的基本框架
- I/O处理单元:处理客户端连接和网络数据的读写
- 逻辑单元:负责业务逻辑的处理
- 网络存储单元:与本地数据库和文件相关
事件处理模式
- reactor 模式:主线程只监听文件描述符上是否有事件发生,若有则通知工作线程读写数据/接受新连接/处理客户端请求。通常由同步IO实现。
- proactor 模式:主线程和内核负责接受新连接/读写数据等IO操作,工作线程只负责处理客户端请求。通常由异步IO实现。
使用同步IO模型模拟proactor模式的工作流程如下:
主线程往epoll内核事件表注册socket上的读就绪事件。
主线程调用epoll_wait等待socket上有数据可读
当socket上有数据可读,epoll_wait通知主线程,主线程从socket循环读取数据,直到没有更多数据可读,然后将读取到的数据封装成一个请求对象并插入请求队列。
睡眠在请求队列上某个工作线程被唤醒,它获得请求对象并处理客户请求,然后往epoll内核事件表中注册该socket上的写就绪事件
主线程调用epoll_wait等待socket可写。
当socket上有数据可写,epoll_wait通知主线程。主线程往socket上写入服务器处理客户请求的结果。
线程池
线程池通常与任务队列搭配使用。当任务队列有新任务到达时,唤醒某个工作线程,它取出队首任务并执行该任务。执行完毕后,该工作线程返回线程池,等待下一次的唤醒。
使用线程池的好处
- 降低资源消耗:线程池通过重用已存在的线程来执行任务,减少了因线程创建和销毁所带来的资源消耗。在并发场景下,频繁地创建和销毁线程会占用大量的系统资源,使用线程池则能有效降低这种消耗。
-
提高响应速度:当任务到达时,线程池能够立即分配空闲线程来执行任务,而无需等待新线程的创建。这可以显著减少任务的等待时间,提高系统的响应速度。
-
控制并发线程数量:在高并发场景下,过多的线程会导致系统资源的浪费和竞争,进而影响应用程序的性能。线程池允许开发人员通过配置核心线程数、最大线程数等参数来控制并发线程的数量,从而避免这种情况的发生。
线程池的代码实现
template <typename T>
class threadpool
{
public:
/*thread_number是线程池中线程的数量,max_requests是请求队列中最多允许的、等待处理的请求的数量*/
threadpool(int actor_model, connection_pool *connPool, int thread_number = 8, int max_request = 10000);
~threadpool();
bool append(T *request, int state);
bool append_p(T *request);
private:
/*工作线程运行的函数,它不断从工作队列中取出任务并执行之*/
static void *worker(void *arg);
void run();
private:
int m_thread_number; //线程池中的线程数
int m_max_requests; //请求队列中允许的最大请求数
pthread_t *m_threads; //描述线程池的数组,其大小为m_thread_number
std::list<T *> m_workqueue; //请求队列
locker m_queuelocker; //保护请求队列的互斥锁
sem m_queuestat; //是否有任务需要处理
connection_pool *m_connPool; //数据库连接池
int m_actor_model; //模型切换
};
template <typename T>
threadpool<T>::threadpool( int actor_model, connection_pool *connPool, int thread_number, int max_requests) : m_actor_model(actor_model),m_thread_number(thread_number), m_max_requests(max_requests), m_threads(NULL),m_connPool(connPool)
{
if (thread_number <= 0 || max_requests <= 0)
throw std::exception();
// 为线程数组分配空间
m_threads = new pthread_t[m_thread_number];
if (!m_threads)
throw std::exception();
// 创建thread_number个线程,并将它们设置为脱离线程
for (int i = 0; i < thread_number; ++i)
{
if (pthread_create(m_threads + i, NULL, worker, this) != 0)
{
delete[] m_threads;
throw std::exception();
}
if (pthread_detach(m_threads[i]))
{
delete[] m_threads;
throw std::exception();
}
}
}
template <typename T>
threadpool<T>::~threadpool()
{
delete[] m_threads;
}
// 向请求队列中添加请求
template <typename T>
bool threadpool<T>::append(T *request, int state)
{
m_queuelocker.lock();
// 如果请求队列的大小大于最大请求数,说明请求队列已满,解锁并返回false
if (m_workqueue.size() >= m_max_requests)
{
m_queuelocker.unlock();
return false;
}
// 将请求添加到请求队列中,解锁,然后信号量加1,唤醒一个线程
request->m_state = state;
m_workqueue.push_back(request);
m_queuelocker.unlock();
m_queuestat.post();
return true;
}
// 向请求队列中添加请求
template <typename T>
bool threadpool<T>::append_p(T *request)
{
m_queuelocker.lock();
if (m_workqueue.size() >= m_max_requests)
{
m_queuelocker.unlock();
return false;
}
m_workqueue.push_back(request);
m_queuelocker.unlock();
m_queuestat.post();
return true;
}
// 工作线程运行的函数
template <typename T>
void *threadpool<T>::worker(void *arg)
{
threadpool *pool = (threadpool *)arg;
pool->run();
return pool;
}
// 工作线程的处理逻辑
template <typename T>
void threadpool<T>::run()
{
while (true)
{
// 等待信号量,即等待请求队列中有任务
m_queuestat.wait();
// 取出请求队列中的队首任务
m_queuelocker.lock();
if (m_workqueue.empty())
{
m_queuelocker.unlock();
continue;
}
T *request = m_workqueue.front();
m_workqueue.pop_front();
m_queuelocker.unlock();
if (!request)
continue;
// 如果反应堆模型为reactor, 工作线程读写网络数据,并处理客户端请求
if (1 == m_actor_model)
{
// 如果需要读网络数据
if (0 == request->m_state)
{
// 如果读取数据成功,接下来处理客户端请求
if (request->read_once())
{
request->improv = 1;
connectionRAII mysqlcon(&request->mysql, m_connPool);
request->process();
}
// 读取数据失败,关闭连接
else
{
request->improv = 1;
request->timer_flag = 1;
}
}
// 如果需要写网络数据
else
{
// 如果写数据成功,接下来注册写事件
if (request->write())
{
request->improv = 1;
}
// 写数据失败,关闭连接
else
{
request->improv = 1;
request->timer_flag = 1;
}
}
}
// 如果反应堆模型为proactor,工作线程只处理客户端请求
else
{
connectionRAII mysqlcon(&request->mysql, m_connPool);
request->process();
}
}
}
#endif