第一章 概念和工具(一)
本篇内容:Windows操作系统的版本、Windows API、服务、函数、例程、进程、线程、作业、纤程。
1.1 Windows系统的版本
作为背景知识,书中列出了基于NT的Windows操作系统各个版本的发布时间:
Windows NT 3.1 1993.7
Windows NT 3.5 1994.9
Windows NT 3.51 1995.5
Windows NT 4.0 1996.7
Windows 2000 (NT5.0) 1999.12
Windows XP (NT5.1) 2001.8
Windows Server 2003 (NT5.2) 2003.3
作为补充,我从网上搜集了非NT系列的Windows操作系统的发布时间:
Windows 1.0 1985-11-20
Windows 2.0 1987-11-1
Windows 3.0 1990-5-22
Windows 95 1995-8-24
Windows 98 1998-6-25
Windows Me 2000-9-14
以及MS-DOS的发布时间:
DOS1.0 1981.8
DOS1.1 1982.5
DOS2.0 1983.3
DOS3.0 1984.8
DOS4.0 1988.6
DOS5.0 1991.6
DOS6.0 1993.3
DOS6.21 1994.2
DOS6.22 1994.6
DOS7.0 1995.8 (随Windows 95发布)
关于DOS的回忆,参见另一篇http://blog.csdn.net/qwang24/archive/2009/05/09/4162679.aspx
1.2 基础概念和术语
Windows API:
l Windows API是Windows操作系统家族的系统编程接口。每个版本的操作实现Windows API的不同子集。
l Win32特指32版本的Windows编程接口。本书用Windows API泛指32位和64位的Windows编程接口。
l Windows API可以分为七大类:基本服务、组件服务、用户界面服务、图形和多媒体服务、消息和协作、网络、Web服务。本书只关注第一类即基本服务的内部实现机理上。
关于.NET和WinFX:
书中提到了.NET和WinFX与Windows API之间的关系。对.NET,书中介绍的基本明确,其层次关系为:用户模式下的.NET应用程序->用户模式下的CLR库->用户模式下的Windows API->内核模式服务。对于WinFX,书中只说是“新的Windows API”,是下一代应用程序的基础平台。没有说清楚。为了理解WinFX到底是什么东西,我从网上查找了相关的资料。WinFX可以简单地理解为Windows API的对等体,即基于WinFX的层次关系为:用户模式下的WinFX应用程序->WinFX->内核模式服务。WinFX如何能不依赖于Windows API而使用内核模式的服务?这是因为在内核服务之上还存在一层Native API调用。Windows API和WinFX都需要调用Native API。如下图:
服务、函数和例程
本节描述几个特定的术语在本书中的含义。
l Windows API函数:文档化的可调用例程,如CreateProcess, CreateFile。
l 原生系统服务:未文档化的底程例程。其实就是上图中的Native API。
l 内核函数:只能在内核模式下调用的例程。
l Windows服务:由服务控制管理器启动的例程。
l DLL:已经被链接成二进制文件的可调用例程库。
进程
关于进程与程序的区别与联系,书中描述的不全面。网上很多关于这方面的描述,摘录一段:
l 进程是动态的,而程序是静态的。
l 进程有一定的生命期,而程序是指令的集合,本身无“运动”的含义。没有建立进程的程序不能作为1个独立单位得到操作系统的认可。
l 1个程序可以对应多个进程,但1个进程只能对应1个程序。进程和程序的关系犹如演出和剧本的关系。
进程的构成元素:
l 私有的虚拟地址空间
l 映射到虚拟地址空间的程序
l 已打开的句柄列表
l 访问令牌(与安全相关)
l 进程ID
l 至少一个线程
其他:
l 子进程的存在不依赖于父进程的存在。
l 进程查看工具:Tlist (Debugging tools for Windows),任务管理器(Windows自带),Proces Explorer (sysinternals.com)。
线程
线程的构成元素:
l 一组CPU寄存器中的内容
l 一个用户模式栈,一个内核模式栈
l 线程局部存储区(TLS)
l 线程ID
l 安全环境(不是必须的)
线程的Context:
包括三个部分:寄存器、栈和私有存储区。可以用GetThreadContext获取。
纤程(Fiber)
对于进程和线程的概念,平时接触的很多,但对于纤程,则用的很少。纤程称为“轻量级”的线程,应用程序自己负责调度它的执行,对于内核是不可见的,它完全是在用户模式下实现的。
Windows为什么要有纤程的概念,什么时候使用纤程,书中并未介绍。下面是从《Windows核心编程》(Winodws Via C/C++)5th Edition中找到的相关知识:
UNIX操作系统不支持多线程,其上的多线程功能是由一个线程函数库实现的,而不是操作系统的功能。这使我想到以前在Linux上开发时,使用的PThread库,它就是Linux上线程函数库的一个实现。为了方便用户把应用程序从UNIX移植到Windows上,Microsoft在Windows上增加了纤程的概念,类似地,纤程也完全是在用户模式下实现。《Windows核心编程》中建议尽量不要使用纤程,而应该使用线程。
作业(Job)
作业的功能是对一组进程当作一个整体进行管理,如活动进程数目限制、CPU时间限制、内存限制等。为什么要有作业的概念,什么时候使用作业,书中没有介绍。第六章对作业有专门一节,翻看一下,也没有涉及。从《Windows核心编程》(Winodws Via C/C++)5th Edition中可以找到了相关的介绍,该书中列举了两种典型的作业应用场合:
用Visual Studio编译一个Project的时候,会生成很多子进程,如果用户提前中止编译,Visual Studio必须能中止所有的子进程。但是因为Windows不维护进程之间父子的关系,所以这一点在Windows中实现起来非常困难。(http://www.microsoft.com/msj/0698/win320698.aspx 介绍了Visual Studio是如何实现这一点的。)但是如果借助于作业,则实现起来要简单的多。顺便看了一下我机器上的Visual Studio 2005,发现它已经这样做了。
设计服务器时,必须把一组进程当作一个单独的组来处理,以限制客户端能请求的东西,如CPU和内存等,避免一个客户端独占资源。这时,也需要用到作业来实现这些限制。