首页 > 代码库 > 详谈内存管理技术(三)、线程模型
详谈内存管理技术(三)、线程模型
一、为什么需要线程模型?
记得几年前,自己写高精度算法时,因为需要一个线程安全的后台(用来保存一些信息),便手动写了一个线程本地存储(TLS)(虽然,后来因为改了计算模型,弃用了);再后来,因为内存池的需要,亦手动再写了一个线程本地存储(TLS);很好,这样一来同一个库里,竟然有两套相同的TLS;于是,意识到了什么地方不对。
不只是代码重复的问题(其实重复的不多);更重要的是,TLS应该是线程模型本身,来提供的功能;但,很可惜,C++并没有这样的东西(线程模型)。(PS:我无视了系统提供的TLS...)
说了这么多;只想说一点:为了TLS,为了性能! 当然,统一的线程模型,会有一个更大的好处:统一且简洁的多线程接口。
二、任务模型
和Java类似,线程模型本身派生与任务模型(我的最初版本并不是);这样有一个好处:将实例化的线程,当作任务来使用(即:并不通过自身所持有的线程,来执行任务)。在一些情形下,会有这样的需求。
作为最根本的接口,需要足够的简单:
class ITask :public Interface{ public: virtual void run() = 0; public: virtual void interrupted(){} public: virtual tick_t getWaitingTime()const{ return 0; } };
最重要、也最直白的便是 run() 这个接口函数;其便是我们将要执行的任务本身(所以无需多言)。值得一提的是:interrupted() 其是一个回调函数,用来通知该任务,执行过程中被意外中断(如抛出异常)。至于 getWaitingTime() 是为线程池准备的,如果你的线程池支持延时执行。
三、线程模型
首先,要明白两点:什么是线程? 它用来做什么??
在面向对象里,线程(类)即能够开启另外一个线程(相对进程);而其目的无外乎,用来执行代码。所以,其包含有两套逻辑:开启新线程、被执行的任务接口。所以,便如下:
class Thread :public ITask{ protected: void execute(); };
其相对于 ITask,只需要提供开启新线程的接口:execute。调用这个函数,便让新线程开始执行 run 所定义的任务。
当然,还远不止如此;我们可以提供更多的控制接口:suspend、resume、interrupt(用来中断线程),以及查询接口:isStarted、threadID。但,有一个接口,绝不能够被遗忘:
class Thread :public ITask{ protected: void execute(); public: void wait();// here~ };
一旦线程开始执行;其最上层(Thread的子类)必须等待,该线程停止运行后,才能够开始析构!!而提供这样等待的便是:wait。(有GC的语言,没有这个问题)
四、线程本地存储
TLS,在哪里??对,我们依旧没有看到其丝毫的身影。其实,就在 execute 的背后——其开启新线程的同时,会注册该新线程,以创建一个新的线程环境(TLS);同样,在该线程停止时,将取消注册,并删除该环境。
这时,我们需要一个全局的线程运行时环境,用来管理所有线程,并存储相应的TLS(或保存其索引)。
当然,有一个问题值得提出:TLS放在哪里? 是全局运行时环境,还是线程本身?(操作系统,一般通过线程自身的调用栈,来存放TLS)
如果,我们真有一个统一的线程模型,二者都可以选择。可惜,我们不可能有!主线程,不可能被我们的任何模型所约束(整个程序的第一行代码执行前,主线程便存在了)。当然,我们可以回避这个问题,通过完全不使用主线程(即:我们的任何逻辑,都在非主线程里执行);而且需要相当的小心,比如静态初始化。
所以,唯一的选择就是,放在全局的运行时环境。这时,我们所见到的大概这样:
void Thread::execute() { GetServiceAs<ThreadService>()->login();
... }
所有的一切,都存放在 ThreadService 里;那么,如何获得TLS,自然也是使用:
... GetServiceAs<ThreadService>()->getLocalAs<XXType>(); ...
需要注意的一点是,我们并没有显示地使用线程ID,来索引;而是在接口内部,通过系统API:GetCurrentThreadId 来获取当前线程ID。
五、其他
很多细节问题,我并没有提及,如:interrupted(),如何使用?
是的,我所有的文章里,都没有“细节”二字;原因有二:并非数十行代码就能够明了、我的库并没有开源。但,相应的,所有的设计过程及细节,都已呈现给各位;只要你不笨,并有一些兴趣和耐心,便不难实现(甚至比我所讲的更好)。
嗯,这次的内容,足够的少;大概是,“累”了,写了一些后,并没有任何同类的人,来进行期待中的交流(主要是期待不同意见);但,没有。所以,我将要动笔的概率,大概也将越来越低......
至此。
详谈内存管理技术(三)、线程模型