首页 > 代码库 > 服务器开发之线程结构

服务器开发之线程结构

线程结构相当于服务器程序的灵魂,一个好的服务器程序必须线程结构清析且线程利用率高。下面主要以伪代码的形式列举一些常用的线程结构。

1 单业务处理线程结构

int main(){	Init();	while (queue.GetMessage(timeout, message)) // 这里的队列要支持多个线程写,一个线程读	{		DispatchMessage(message);		DetectTimer(); // 如果需要定时器的话	}	DeInit();	return 0;}

windows窗口程序及我见过的大部分网游服务器都使用这种线程结构。因为只有一个业务处理主线程,在进行业务处理的时候,不需要考虑线程同步。当然这种服务器并不只是只有一个线程在工作,通常网络和DB(如果有的话)会使用独立的线程,例如当网络收到一个消息后,就Enqueue到队列中,这时queue.GetMessage返回,由DispatchMessage找到对应的处理函数去做具体的处理。

 

2 多业务处理线程

int main(){	Init();	for (1 to 10)	{		StartThread(&ThreadFunction);	}	WaitForExit();	DeInit();	return 0;}int ThreadFunction(){	while (queue.GetMessage(timeout, message)) // 队列要支持多写多读	{		DispatchMessage(message);	}	return 0;}

网络线程收到消息后,Enqueue到队列,其中一个线程的GetMessage会返回并处理。DB模块通常使用这种线程结构。

 

3 并发单线程

class WorkThread{public:	void Start();private:	void AsnycRead(int clientId);	void AsnycWrite(int clientId, Message* message);	void OnRead(int clientId, Message* message);	void OnWriteComplite(int clientId);};int main(){	for (1 to 10)	{		new WorkThread();	}	WaitForExit();	return 0;}

我其实没找到一个好的名称和伪代码去描述这种线程结构,多加点文字说明吧。这种线程结构通常在程序启动时开启多个线程(通常是CPU核芯数),每个线程完整的加载其需要的配置,每个线程都是独立的且功能都是一样的,线程与线程之间没有仍何交互,用户代码中没有队列。一个连接建立好后,始终在同一个线程空间中运行,因此也没有任何线程同步。这种线程序结构非常适合网关类、转发类等慢操作比较少的服务器,能充分利用多核的CPU资源,提高服务效率。使用iocp及boost.asio很容易实现这种线程结构。

 

4 线程池

int main(){	Init();	for (1 to 100)	{		ThreadPool.Add(new WorkThread());	}	WaitTask();	WaitForExit();	DeInit();	return 0;}void WaitTask(){	WorkThread t = ThreadPool.GetFree();	t.Wakeup(); // 唤醒子线程后立即返回,子线程等待客户端连接,连接成功后先Wakeup下一个线程去等待客户端连接, 由本线程执行任务}

曾经比较火的Leader/Follower模式,据说tomcat用的就是这个,但个人觉得这种结构效率并不高,因为这种模式网络IO通常用同步,大大降低了线程的利用率。

 

结束语

以上只上对线程结构的简化描述,实际用到的服务器并不会只这么简单,可能是多种结构的组合,也可能是上面没提到的线程结构。但高并发高效率的服务器要点其实很简单:提高每个线程的利用率,尽量避免忙等、睡眠及过多的线程切换,同时减少加锁及各种队列的入列出列。业务处理方面可将业务细化,由单服务器处理转成多服务器处理,能并发的就并发……不过这超出了本文的范围,有机会再详述。

 

附感言

在08年之前,boost还不是那么流行,我通常会使用自己实现的线程相关的基础库,如Mutex, Condition, Thread, SharedPtr, MessageQueue——当然基本上也是从boost中抄过来的。时间飞奔,2016年的现在,C11也包含了以上大部分库,还剩MessageQueue实现起来也是分分钟的事……时代更美好了!

服务器开发之线程结构