在Windows NT产品线(包括Windows 2000和Windows XP)中,任务管理器工具是不可或缺的。通过按下CTRL+SHIFT+ESC键,可以激活该工具,它将显示当前活动的进程列表,并允许用户进行多种操作:启动新进程、停止进程以及设置它们的优先级。当某个进程占用大量资源(通常是CPU时间)时,用户可以轻松地将其优先级设置为最低,系统将负责分配剩余资源或机器上的“空闲时间”。
尽管任务管理器功能强大,但一直希望Windows能够提供暂停和恢复进程的功能,这在其他操作系统中是常见的。以下是一些实际场景,其中这一功能将非常有用:
实现这一功能的主要障碍是:没有名为SuspendProcess的API函数。也没有文档记录或安全的方法来实现这一点。唯一简单的方法是通过SuspendThread/ResumeThread这对API函数。这对函数允许暂停和恢复线程。为了安全起见,它们维护了一个内部的“挂起计数”。每次调用SuspendThread时,都会增加这个计数器。另一方面,调用ResumeThread会减少这个计数器。如果不是这样做,调用SuspendThread的调用者将无法知道如何恢复线程的原始状态。在调用SuspendThread之后调用ResumeThread将有效地恢复原始线程的状态。
了解这一点后,暂停一个进程就变得非常简单了:只需要列出进程的所有线程,为每个线程打开一个句柄,并调用SuspendThread。恢复操作也是以相同的方式完成的。ToolHelp32 API提供了一些函数,可以轻松地列出系统上的线程和进程。实际上,代码中有两个函数是无耻地从MSDN示例中借用的。
因此,编写了这个小型命令行实用程序(有一个将其与任务管理器集成的想法,但目前还没有时间去做)。如何使用它,建议将可执行文件放在PATH的任何位置。Windows目录将是一个很好的选择。始终在不依赖CRT的DLL的情况下编译这个程序,这样程序启动会更快。可能在非常不利的条件下启动这个程序,所以寻找MSVCRT*.DLL并加载它可能会在启动时间上产生巨大的差异。
与大多数命令行工具一样,它旨在从命令提示符中使用,通过点击“命令提示符”快捷方式或打开Start/Run并执行cmd.exe。程序的用法非常简单:
pausep PID [/r]
如果只输入pausep而不带参数,程序将显示其用法以及正在运行的进程及其PID列表。如果输入pausep PID,程序将对进程的所有线程调用SuspendThread。这将暂停线程或增加它们的挂起计数。如果传递了/r参数,程序将执行相反的操作,即恢复线程。请注意,如果在没有恢复的情况下三次暂停同一个进程,也需要使用pausep /r三次。
这种方法存在风险:并非所有程序都编写得很好。并非所有程序都适合暂停,特别是多线程程序。实现超时的程序如果在暂停和恢复时可能会异常行为。当以任意顺序暂停和恢复线程时,就像使用这个实用程序一样,可能会创建死锁。
因此,只有在知道自己在做什么的情况下才使用这个程序。