并行思维(三)2011-06-23 博客园 Angel Lucifer线程是什么玩意对于并行程序设计来说,线程的重要性不言而喻。现代操作系统是典型的基于抢占式调度机制的多任务操作系统。所谓多任务,指同一时刻,允许操作系统内有多个应用程序运行。比如,我们可以在同一时刻,一边收听音乐,一边浏览网页。当然,计算机能做到的远不止于此。所谓抢占式调度机制,指在操作系统强制让另外的应用程序运行之前,正在运行的应用程序究竟可以占用 CPU 多少时间。这正是为什么我们感觉多个应用程序同时运行的真正原因,即使在单核处理器上。举例来说,Windows 操作系统任务调度的时间间隔大约在 20 毫秒左右(注:这个极短的时间,人眼无法感知,而人眼又欺骗了大脑,我们就感觉有多个程序在同时运行。实践所知,人眼能感知的最小时间大概是 100 毫秒。因此,Windows Client UI 开发人员应当注意,千万不要让你的程序界面响应大于 100 毫秒。假如大于此数,客户就会感到界面顿卡,带来槽糕的用户体验。Web UI 可以适当放宽界限。但无论怎样,快速的响应策略应当成为实现良好用户体验的首选)。每个正在运行的应用程序实例都是一个进程。进程通常相对独立于其他进程运行。尤其是程序所使用的内存资源。举个例子,浏览器一般都不能直接访问音乐播放器的内存资源。如果有这个需求,则需要通过其他手段来达到该目的。比如文件映射,IPC,Socket 等机制。当然,这些机制通常比直接访问内存资源花费的时间要多。拿最广泛应用的 Windows 操作系统而言,从软件开发人员的角度来看,进程其实就是个计算机资源集合。它是 Windows 操作系统分配和使用系统资源的基本单位。Windows 进程均包含以下资源:一个或多个线程。Linux 操作系统早期使用进程来模拟线程。一个虚拟地址空间,该空间独立于其他进程地址空间。当然显式共享的内存除外。请注意文件映射共享物理内存,但共享进程使用不同的虚拟地址来访问这些映射文件。一个或多个代码段,包括 DLL 中的代码。一个或多个包含全局变量的数据段。环境字符串,包含环境变量信息。进程堆。其他资源,比如打开的句柄和其他的堆。而进程的每个线程则共享代码,全局变量,环境字符串等资源。每个线程都独立进行调度,是最基本的可执行单元,并包含以下资源:为过程调用、中断、异常处理器和自动存储建立的堆栈。线程本地存储(TLS),这是个指针数组,可以让线程分配存储以创建其特有的数据环境。堆栈参数,在创建线程时生成,对每个线程来说通常唯一。上下文结构,由系统内核通过机器注册表值来维护。对于 .NET 开发人员来说,情况又有些不同。CLR 保留了与 Windows 线程分离的权利,而且在某些寄宿情形中,CLR 线程并没有与 Windows 线程准确匹配。比如,宿主可以告诉 CLR 将每个 CLR 线程表示为一个 Windows 纤程(Fiber)(注:纤程是轻量级的线程。Windows 对纤程一无所知)。图 1 展示了一个拥有多线程的 Windows 进程。注意,该图只是示意图,没有展示实际内存地址,也没有按照比例绘制。

图 1 Windows 进程示意图