7.2 暂停和恢复进程的运行
对于Windows来说,不存在暂停或恢复进程的概念,因为进程从来不会被安排获得CPU时间。但是,曾经有人无数次问我如何暂停进程中的所有线程的运行。Windows确实允许一个进程暂停另一个进程中的所有线程的运行,但是从事暂停操作的进程必须是个调试程序。特别是,进程必须调用WaitForDebugEvent和ContinueDebugEvent之类的函数。
由于竞争条件的原因,Windows没有提供其他方法来暂停进程中的所有线程的运行。例如,虽然许多线程已经暂停,但是仍然可以创建新线程。从某种意义上说,系统必须在这个时段内暂停所有新线程的运行。Microsoft已经将这项功能纳入了系统的调试机制。
虽然你无法创建绝对完美的SuspendProcess函数,但是你可以创建一个该函数的实现代码,它能够在许多条件下出色地运行。下面是我的SuspendProcess函数的实现代码:            见原书P217的程序(1)我的SuspendProcess函数使用ToolHelp函数(第4章中做了介绍)来枚举系统中的线程列表。当我找到作为指定进程的组成部分的线程时,我调用OpenThread:             见原书P217的程序(2)这个新Windows 2000函数负责找出带有匹配的线程ID的线程内核对象,对内核对象的使用计数进行递增,然后返回对象的句柄。运用这个句柄,我调用SuspendThread(或ResumeThread)。由于OpenThread在Windows 2000中是个新函数,因此我的SuspendProcess函数在Windows 95或Windows 98上无法运行,在Windows NT 4.0或更早的版本上也无法运行。
也许你懂得为什么SuspendProcess不能在100%的时间内运行,原因是当枚举线程组时,新线程可以被创建和撤消。因此,当我调用CreateToolhelp32Snapshot后,一个新线程可能会出现在目标进程中,我的函数将无法暂停这个新线程。过了一些时候,当你调用SuspendProcess函数来恢复线程的运行时,它将恢复它从未暂停的一个线程的运行。更糟糕的是,当枚举线程ID时,一个现有的线程可能被撤消,一个新线程可能被创建,这两个线程可能拥有相同的ID。这将会导致该函数暂停任意某个(也许在目标进程之外的一个进程中的)线程的运行。
当然,这些情况不太可能出现,并且,如果你非常了解目标进程是如何运行的,那么这些问题也许根本不是问题。我为你提供这个函数,你可以酌情使用。

解决方案 »

  1.   


    7.7 线程的优先级
    在本章的开头,我讲述了CPU是如何只使线程运行20毫秒,然后调度程序将另一个可调度的线程分配给CPU的。如果所有线程具有相同的优先级,那么就会发生这种情况,但是,在现实环境中,线程被赋予许多不同的优先级,这会影响到调度程序将哪个线程取出来作为下一个运行的线程。
    每个线程都会被赋予一个从0(最低)到31(最高)的优先级号码。当系统要确定将哪个线程分配给CPU时,它首先观察优先级为31的线程,并以循环方式对它们进行调度。如果优先级为31的线程可以调度,那么就将该线程赋予一个CPU。在该线程的时间片结束时,系统要查看是否还有另一个优先级为31的线程可以运行,如果有,它将允许该线程被赋予一个CPU。
    只有优先级为31的线程才可以调度,系统将绝对不会将优先级为0到30的线程分配给CPU。这种情况称为渴求调度(starvation)。当高优先级线程使用如此多的CPU时间,从而使得低优先级线程无法运行时,便会出现渴求情况。在多处理器计算机上出现渴求情况的可能性要少得多,因为在这样的计算机上,优先级为31和优先级为30的线程能够同时运行。系统总是设法使CPU保持繁忙状态,只有当没有线程可以调度的时候,CPU才处于空闲状态。
    你可能认为,在这样的系统中,低优先级线程永远得不到机会运行。不过正象我已经指出的那样,在任何一个时段内,系统中的大多数线程是不能调度的。例如,如果你的进程的主线程调用GetMessage函数,而系统发现没有线程可以供它使用,那么系统就暂停你的进程的线程运行,释放该线程的剩余时间片,并且立即将CPU分配该另一个等待运行的线程。
    如果没有为GetMessage函数显示可供检索的消息,那么进程的线程将保持暂停状态,并且决不会被分配给CPU。但是,当消息被置于线程的队列中时,系统就知道该线程不应该再处于暂停状态,于是,如果没有更高优先级的线程需要运行,就将该线程分配给一个CPU。
    现在我想提醒你注意另一个问题。高优先级线程将抢在低优先级线程之前运行,不管低优先级线程正在运行什么。例如,如果一个优先级为5的线程正在运行,系统发现一个高优先级的线程准备要运行,那么系统就会立即暂停低优先级线程的运行(即使它处于它的时间片的中间),并且将CPU分配给高优先级线程,使它获得一个完整地时间片。
    顺便我要指出,当系统引导时,它会创建一个特殊的线程,称为0页线程。该线程被赋予优先级0,它是整个系统中唯一的一个在优先级0上运行的线程。当系统中没有任何线程需要执行操作时,0页线程负责将系统中的所有空闲RAM页面置0。
      

  2.   


    7.7 线程的优先级
    在本章的开头,我讲述了CPU是如何只使线程运行20毫秒,然后调度程序将另一个可调度的线程分配给CPU的。如果所有线程具有相同的优先级,那么就会发生这种情况,但是,在现实环境中,线程被赋予许多不同的优先级,这会影响到调度程序将哪个线程取出来作为下一个运行的线程。
    每个线程都会被赋予一个从0(最低)到31(最高)的优先级号码。当系统要确定将哪个线程分配给CPU时,它首先观察优先级为31的线程,并以循环方式对它们进行调度。如果优先级为31的线程可以调度,那么就将该线程赋予一个CPU。在该线程的时间片结束时,系统要查看是否还有另一个优先级为31的线程可以运行,如果有,它将允许该线程被赋予一个CPU。
    只有优先级为31的线程才可以调度,系统将绝对不会将优先级为0到30的线程分配给CPU。这种情况称为渴求调度(starvation)。当高优先级线程使用如此多的CPU时间,从而使得低优先级线程无法运行时,便会出现渴求情况。在多处理器计算机上出现渴求情况的可能性要少得多,因为在这样的计算机上,优先级为31和优先级为30的线程能够同时运行。系统总是设法使CPU保持繁忙状态,只有当没有线程可以调度的时候,CPU才处于空闲状态。
    你可能认为,在这样的系统中,低优先级线程永远得不到机会运行。不过正象我已经指出的那样,在任何一个时段内,系统中的大多数线程是不能调度的。例如,如果你的进程的主线程调用GetMessage函数,而系统发现没有线程可以供它使用,那么系统就暂停你的进程的线程运行,释放该线程的剩余时间片,并且立即将CPU分配该另一个等待运行的线程。
    如果没有为GetMessage函数显示可供检索的消息,那么进程的线程将保持暂停状态,并且决不会被分配给CPU。但是,当消息被置于线程的队列中时,系统就知道该线程不应该再处于暂停状态,于是,如果没有更高优先级的线程需要运行,就将该线程分配给一个CPU。
    现在我想提醒你注意另一个问题。高优先级线程将抢在低优先级线程之前运行,不管低优先级线程正在运行什么。例如,如果一个优先级为5的线程正在运行,系统发现一个高优先级的线程准备要运行,那么系统就会立即暂停低优先级线程的运行(即使它处于它的时间片的中间),并且将CPU分配给高优先级线程,使它获得一个完整地时间片。
    顺便我要指出,当系统引导时,它会创建一个特殊的线程,称为0页线程。该线程被赋予优先级0,它是整个系统中唯一的一个在优先级0上运行的线程。当系统中没有任何线程需要执行操作时,0页线程负责将系统中的所有空闲RAM页面置0。
      

  3.   

    这是什么书?windows 核心编程???有电子版没有?