5.3 终止作业中的所有线程

5.3  终止作业中的所有线程

对于作业,我们经常想做的一件事情就是“杀死”作业中的所有进程。本章伊始,我提到Visual Studio没有一个简单的办法来停止正在进行中的构建(build),因为它必须知道哪些进程是从它生成的第一个进程生成的。(这非常难。我在Microsoft Systems Journal 1998年6月期的Win 32 Q&A专栏讨论过Developer Studio是如何做到这一点的,可以通过以下网址找到这篇文章:http://www.microsoft.com/msj/0698/win320698.aspx。)也许Visual Studio未来的版本会转而使用作业,因为这样一来,代码的编写会变得更容易,而且可以用作业来做更多的事情。

                                                                  

要“杀死”作业内部的所有进程,只需调用以下代码:

BOOL TerminateJobObject(

    HANDLE hJob,

    UINT uExitCode);

这类似于为作业内的每一个进程调用TerminateProcess,将所有退出代码设为uExitCode。

查询作业统计信息

前面讨论了如何使用QueryInformationJobObject函数来查询作业当前的限制。此外,我们还可以用它来获得作业的统计信息。例如,要获得基本的统计信息,我们可以调用函数QueryInformationJobObject,向第2个参数传递JobObjectBasicAccountingInformation和一个JOBOBJECT_BASIC_ACCOUNTING_INFORMATION结构的地址:

typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION {

    LARGE_INTEGER TotalUserTime;

    LARGE_INTEGER TotalKernelTime;

    LARGE_INTEGER ThisPeriodTotalUserTime;

    LARGE_INTEGER ThisPeriodTotalKernelTime;

    DWORD TotalPageFaultCount;

    DWORD TotalProcesses;

    DWORD ActiveProcesses;

    DWORD TotalTerminatedProcesses;

} JOBOBJECT_BASIC_ACCOUNTING_INFORMATION,

    *PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION;

表5-5简要描述了该结构的成员。

表5-5  JOBOBJECT_BASIC_ACCOUNTING_INFORMATION结构的成员

成  员

描  述

TotalUserTime

指出作业中的进程已使用了多少用户模式的CPU时间

TotalKernelTime

指出作业中的进程已使用了多少内核模式的CPU时间

ThisPeriodTotalUserTime

与TotalUserTime一样,不同的是,如果调用SetInformationJobObject来更改基本限额信息,同时没有使用JOB_OBJECT_LIMIT_ PRESERVE_JOB_TIME限额标志,这个值被重置为0

ThisPeriodTotalKernelTime

与ThisPeriodTotalUserTime一样,不同的是,这个值显示的是内核模式CPU时间

TotalPageFaultCount

指出作业中的进程产生的页面错误总数

TotalProcesses

指出曾经属于作业一部分的所有进程的总数

ActiveProcesses

指定作业的当前进程的总数

TotalTerminatedProcesses

指出因为已超过预定CPU时间限额而被“杀死”的进程数

                                                                  

从StartRestrictedProcess函数实现的末尾可以看出,通过调用GetProcessTimes函数我们可以获得任何一个进程的CPU占用时间信息,即使此进程不属于任何一个作业,详情请参见第7章。

除了查询基本的统计信息,还可以执行一个调用来同时查询基本统计信息和I/O(输入/输出)统计信息。为此,要向第2个参数传递JobObjectBasicAndIoAccountingInformation和一个JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION结构的地址:

typedef struct JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION {

    JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo;

    IO_COUNTERS IoInfo;

} JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION,

    *PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION;

可以看出,这个结构返回了JOBOBJECT_BASIC_ACCOUNTING_INFORMATION和一个IO_COUNTERS结构:

typedef struct _IO_COUNTERS {

    ULONGLONG ReadOperationCount;

    ULONGLONG WriteOperationCount;

    ULONGLONG OtherOperationCount;

    ULONGLONG ReadTransferCount;

    ULONGLONG WriteTransferCount;

    ULONGLONG OtherTransferCount;

} IO_COUNTERS, *PIO_COUNTERS;

这个结构指出已由作业中的进程执行过的读操作、写以及非读/写操作的次数(以及这些操作期间传输的字节总数)。顺便说一句,对于那些不属于任何作业的进程,我们可以使用GetProcessIoCounters函数来获得未放入作业的那些进程的信息,如下所示:

BOOL GetProcessIoCounters(

    HANDLE hProcess,

    PIO_COUNTERS pIoCounters);

任何时候都可以调用QueryInformationJobObject,获得作业中当前正在运行的所有进程的进程ID集。为此,必须首先估算一下作业中有多少个进程,然后,分配一个足够大的内存块来容纳由这些进程ID构成的一个数组,另加一个JOBOBJECT_BASIC_PROCESS_ID_LIST结构的大小:

typedef struct _JOBOBJECT_BASIC_PROCESS_ID_LIST {

    DWORD NumberOfAssignedProcesses;

    DWORD NumberOfProcessIdsInList;

    DWORD ProcessIdList[1];

} JOBOBJECT_BASIC_PROCESS_ID_LIST, *PJOBOBJECT_BASIC_PROCESS_ID_LIST;

                                                                  

所以,为了获得作业中当前的进程ID集,必须执行以下类似的代码:

void EnumProcessIdsInJob(HANDLE hjob) {

    // I assume that there will never be more

    // than 10 processes in this job.

    #define MAX_PROCESS_IDS 10

    // Calculate the number of bytes needed for structure & process IDs.

    DWORD cb = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) +

         (MAX_PROCESS_IDS – 1) * sizeof(DWORD);

    // Allocate the block of memory.

    PJOBOBJECT_BASIC_PROCESS_ID_LIST pjobpil =

         (PJOBOBJECT_BASIC_PROCESS_ID_LIST)_alloca(cb);

    // Tell the function the maximum number of processes

    // that we allocated space for.

    pjobpil->NumberOfAssignedProcesses = MAX_PROCESS_IDS;

    // Request the current set of process IDs.

    QueryInformationJobObject(hjob, JobObjectBasicProcessIdList,

        pjobpil, cb, &cb);

    // Enumerate the process IDs.

    for (DWORD x = 0; x < pjobpil->NumberOfProcessIdsInList; x++) {

        // Use pjobpil->ProcessIdList[x]...

    }

    // Since _alloca was used to allocate the memory,

    // we don’t need to free it here.

}

这就是使用这些函数所能获得的所有信息。但是,操作系统实际保存着与作业相关的更多的信息。这是通过性能计数器来实现的,可以使用性能数据助手(Performance Data Helper)函数库(PDH.dll)中的函数来获取这些信息。还可以使用管理工具中的可靠性和性能监视器(Reliability and Performance Monitor)来查看作业信息。但是,这样只能看到全局命名的作业对象。不过,利用Sysinternals的Process Explorer(http://www.microsoft.com/technet/sysinternals/ProcessesAndThreads/ProcessExplorer.mspx),可以很好地观察作业。默认情况下,作业限制下的所有进程都用棕色来突出显示。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值