Processes, Threads, and Jobs尽管从表面上来看进程和程序很像, 但他们本质上是不同的两个概念. 程序是一个静态的指令序列, 然而进程是一个包含程序实例运行时所需要资源的一个容器. 从更高层次上来看Windows 进程包含如下内容:
· 一个私有的虚拟地址空间,即一系列可供进程使用的虚拟内存地址。
· 一个可执行的程序,即被定义好的并且被映射到进程虚拟地址空间的初始代码和数据。
· 一个公开的各种系统资源局并列表: 信号量, 通讯端口, 和文件, 他们可以被进程中的所有线程访问。
· 一个被称为访问令牌的安全上下文(一个对象,封装了跟安全有关的两个实体之间的共享状态信息)用来识别用户,组权限,和进程特权。
· 一个被称为进程Id的唯一标示符(internally called a client ID)
· 至少一个可执行的线程。
每个进程都指向其父进程或者进程创造者(creator process)。也可能指向一个不存在的父进程,但这并不会出现什么问题,因为没有任何其他的对象依赖与此信息的存在,下面的实验说明了这种情况.
tlist /t:
C:\>tlist /t
System Process (0)
System (2)
smss.exe (21)
csrss.exe (24)
winlogon.exe (35)
services.exe (41)
spoolss.exe (69)
llssrv.exe (94)
LOCATOR.EXE (96)
RpcSs.exe (112)
inetinfo.exe (128)
lsass.exe (44)
nddeagnt.exe (119)
explorer.exe (123) Program Manager
OSA.EXE (121)
WINWORD.EXE (117) Microsoft Word - msch02(s).doc
cmd.exe (72) Command Prompt - tlist /t
tlist.EXE (100)
这个列表的缩进显示了进程的父/子关系. 靠近最左边的说明他的父进程不存在(像 Explorer.exe) 我们不能找到其祖父进程,即使其祖父进程存在。因为 Windows只维护其父进程ID,并不能连接到父进程的父进程。
为了证明Windows并不知道除父进程之外的其他进程ID,请依照下面步骤:
1. 打开 window命令提示符.
2. 键入CMD命令(打开第二个命令提示符).
3. 打开任务管理器.
4. 切换到第二个命令提示符.
5. 键入 mspaint命令 (运行windows的图画).
6. 选中第二个命令提示符窗口.
7. 键入 exit命令. (注意 图画 窗口依然存在.)
8. 切换到任务管理器.
9. 选择应用程序标签.
10.选择进程标签.
11.选中 cmd.exe进程.
12.右键结束进程树.
13.在跳出的消息匡中选择YES.
第一命令提示符窗口消逝,但是你仍旧可以看到图画窗口,因为它是你刚刚结束进程的孙进程并且其父进程已经中止,所以图画进程不和任何其他进程有联系。
有很多工具都可以用来查看和修改进程及进程可用信息,下面的试验用于展示可以用那些工具获得的进程信息,这些工具都是windows 自带的(在Windows Support Tools, Windows Debugging Tools, Windows resource kits, the Platform SDK中可以找到)或者可以从http://www.sysinternals.com下载。那些工具中的大部分再显示关于内核进程和线程的信息时都几乎雷同,不过有时可能名字不相同。.
可能我们用得最多最广泛的关于察看进程活动状况的工具是任务管理器(有趣的是,在windows的内核中并没有任何关于“任务”的东西,所以任务管理器其实是一个真正的进程管理器)。下面的实验显示了在任务管理器中列出的应用程序和进程的不同之处。
你可以在任务管理器的应用程序窗口中右键找到转到进程菜单然后找到与其对用的进程。
进程浏览器比其他任何可用的工具现实的更加详细,我们在本书的很多地方都要用到此工具,下面列出了只用进程浏览器工具才能显示得信息:
· 可以显示正在执行的映像文件的完整路径。
· 进程的安全令牌 (list of groups and privileges)
· 高亮显示进程和线程的变化
· List of services inside service-hosting processes, including display name and description
· 进程所在作业名称及其描述。
· 运行在.NET/WinFX 的应用程序的进程和.NET细节描述 (如:CLR执行计数和应用程序域列表)
· 进程和线程的开始时间
· 内存映射文件的完整列表 (not just DLLs)
· 挂起进程的能力
· kill 掉单个线程的能力
· 很容易识别出消耗大量CPU资源(CPU时间)的进程(The Performance Tool can display process CPU utilization for a given set of processes, but it won't automatically show processes created after the performance monitoring session has started.)
Process Explorer 同样提供了浏览进程可用信息的易用工具, 例如:
· 进程树 (with ability to collapse parts of the tree)
· Open handles in a process without prior setup (The Microsoft tools to show open handles require the setting of a systemwide flag and a reboot before they can be used.)
· 进程中DLL文件和内存映射文件列表
· 进程中活动线程
· 用户模式中的线程栈 (including mapping of addresses to names using the debugging tools' symbol engine)
· 内核模式下的系统线程栈 (including mapping of addresses to names using the debugging tools' symbol engine)
· Context switch delta (a better representation of CPU activity, as explained in Chapter 6)
· Kernel memory (paged and nonpaged pool) limits (other tools show only current size)
下面我们将要进行的试验要说明process explor的用法.
选中一个进程双击将会出现关于进程属性的各种信息(在后继章节中我们要多次用到这些信息并会给予解释)
线程是Windows 可调度来执行的进程内实体,如果没有线程进程程序将不能运行,一个线程包含一下主要组成部分:
· 一系列用来描述CPU状态的CPU寄存器的内容。
· 供线程在不同模式(用户模式和内核模式)下使用的两个堆栈。
· 一个被子系统(subsystems),运行时库(run-time libraries),动态连接库(DLLs)使用的称为线程本地存储器 (TLS)的私有存储区域 。
· 一个被称为线程ID的唯一标示符(在系统内部也被称为客户 ID—进程ID和线程ID同出与一个命名空间所以他们永远不会重复).
· 线程有时候有自己的安全上下文,他们通常被用在多线程的服务器应用程序中用来给他所提供服务的客户端赋予不同的权限。
这些易失性寄存器,堆栈,以及这些私有存储区域被称为线程上下文, 在不同的体系结构上运行windows 这些上下文信息也会不同,windows提供GetThreadContext 用来读取具体线程上下文结构结构细节方面的信息.
Fibers vs. Threads纤程(纤程是在用户模式下实现的,内核并不知道纤程的存在,这与线程不同,线程是由内核实现的。并且,纤程采用非抢占式调用方式。一个线程中可以包含一个或多个纤程。但,线程每次只能执行一个纤程的代码。当使用纤程时,必须使用ConvertThreadToFiber函数来将现有的线程转换成一个纤程。还可使用CreateFiber来创建另一个纤程)允许应用程序调度属于他自己的"threads"执行而不是依赖于windows内建的基于优先权的调度机制,
纤程通常被称为“轻线程”,在调度方面,他们对于内核来说是不可见的,因为他们在Kernel32.dll的用户模式下运行,当使用纤程时,必须使用ConvertThreadToFiber函数来将现有的线程转换成一个纤程。然后,新的纤程可使用CreateFiber来创建另一个纤程(每个纤程可以有自己的纤程集)。和线程不同纤程必须使用函数SwitchToFiber手工调度执行,并且一直运行直到他自己退出或者调用SwitchToFiber函数