要设计一个服务器,有两种方法:
一种是自顶向下进行设计。先确定它的功能、然后确定接口,业务流程、数据流、实体关系、模块设计、详细设计、代码开发、单元测试。这种一般用于技术成熟、需求明确、需求变动较小的情况。这种方式就是有名的瀑布开发方法
另外一种这是自底向上进行设计。先把最基本的单元模块完成,然后逐渐向需求靠近。一开始只有一个初步的架构,然后逐步迭代,不断接近需求。当需求方需求可能出现反复修改,或者需求方本身也不清楚自己需求的情况下,这种方式开发会比较合适。这种方式就是有名的原型开发方法
这两种各有各的优缺点和实用场景,没有孰优孰劣,也无法相互彻底进行迭代
需求分析中明显感觉到需求分析不充分,重要的需求不明确,那么这种项目,就要考虑自底向上进行项目开发
无论服务器最后的需求是什么,一个高性能的,高并发的服务器才是最终的需求
那么线程就一定无法回避
所以先从线程开始 就一定不会错
那么,现在一个明确的需求就出现了:
- 我们需要一个线程类,具体的线程函数应该是实际需要的时候在设置
- 不应该限制线程函数的参数数量、作用域(可以是全局函数、静态函数、类成员函数等等)。
- 我们规定线程函数返回值是int,0表示任务结束 1表示需要再次运行任务。
- 线程应该可以控制,在需要的时候启动,并且随时可以终止和退出
- 这个类不应该具有赋值和复制构造函数方法,因为线程本身不具有可复制性
考虑到第二点,我们必然需要泛型编程技术,或者叫模板编程技术
基于这些需求我们大概有一个初步的构想
类名CThread
考虑到很多地方都这么给线程起名,所以我们可以加入一个名称空间
接口也应该有:
- 启动/恢复
- 暂停
- 停止
- 重新开始线程
- 线程是否有效
线程API我们选取Windows下的CreateThread
这个API函数说明如下:
HANDLE
WINAPI
CreateThread(
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,//线程属性
_In_ SIZE_T dwStackSize,//线程栈的大小。为0表示默认大小
_In_ LPTHREAD_START_ROUTINE lpStartAddress,//线程入口函数
_In_opt_ __drv_aliasesMem LPVOID lpParameter,//线程参数
_In_ DWORD dwCreationFlags,//创建标志默认0, CRTEATE_SUSPENDED 线程暂停
_Out_opt_ LPDWORD lpThreadId//线程ID
);
从上面我们可以知道,线程API接口需要我们填入一个__stdcall调用约定的函数,来作为系统API的参数
考虑到线程后面可能用于线程池,所以线程类本身不能是模板类
注意:模板参数一旦不同,系统会认为这些类是不同的类,所以用于线程池的时候,会比较麻烦——我们不太可能给每一个子线程提供控制接口,因为线程池要求所有子线程最好都是一个类型,这样扩容或收缩的时候,就容易实现动态分配和释放
所以我们还需要一个模板函数类,来接入这些用户动态设置的自定义线程函数
由于这个函数类是模板类,所以我们还需要来给它设置一个基类,方便线程类来持有它
避免模板参数的需求传递到线程类来了
注意:函数类也叫仿函数,一般需要重构函数调用运算符 operator()(...)。