演示作业的使用及获取统计信息
演示作业的使用及获取统计信息
演示作业的使用及获取统计信息
/*
演示作业的使用及获取统计信息
*/
#include <stdio.h>
#include <Windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <malloc.h> // for _alloca函数
#include <locale.h>
void EnumProcessIdsInJob(HANDLE hJob);//获取作业中当前的进程ID集
void StartRestrictedProcess();//利用作业对象对进程进程管理的演示
int _tmain()
{
_tsetlocale(LC_ALL, TEXT("chs"));
StartRestrictedProcess();
return (0);
}
//获取作业中当前的进程ID集
void EnumProcessIdsInJob(HANDLE hJob)
{
//先假设作业中的进程不会超过10个
const int MAM_PROCESS_IDS = 10;
//计算结构体和ID集所需的控件大小
DWORD cb = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) +
(MAM_PROCESS_IDS - 1) * sizeof(DWORD);
//分配内存,注意_allocal是在栈(而不是堆上分配的,所有不需要释放)
PJOBOBJECT_BASIC_PROCESS_ID_LIST pjobpil =
(PJOBOBJECT_BASIC_PROCESS_ID_LIST)_alloca(cb);
//估计最多的线程数
pjobpil->NumberOfAssignedProcesses = MAM_PROCESS_IDS;
//查询
QueryInformationJobObject(hJob, JobObjectBasicProcessIdList, pjobpil, cb, &cb);
//显示进程ID集
for (DWORD x = 0; x < pjobpil->NumberOfProcessIdsInList; x++)
{
_tprintf(TEXT("process %d(ID = %d)\n"), x + 1, pjobpil->ProcessIdList[x]);
}
}
//利用作业对象对进程进程管理的演示
void StartRestrictedProcess()
{
//检查进程是否已经包含在作业中
// 如果已经关联。就没犯法在换到另外一个作业对象中去
/*屏蔽测试
BOOL bInJob = FALSE;
IsProcessInJob(GetCurrentProcess(), NULL, &bInJob);
if (bInJob)
{
_tprintf(_T("Process already in a job\n"));
return;
}*/
//创建作业内核对象
HANDLE hJob = CreateJobObject(NULL,
TEXT("MyRestrictedProcessJob"));
//在作业中放入线程对象的一些限制规则
//首先,设置基本限制
JOBOBJECT_BASIC_LIMIT_INFORMATION jobli = { 0 };
//进程总是运行在“空闲”优先级
jobli.PriorityClass = IDLE_PRIORITY_CLASS;
//该作业对象在用户模式下不能超过1ms的cpu时间
jobli.PerJobUserTimeLimit.QuadPart = 1000 * 10000I64;
//10000tick = 10000*100ns = 1ms
//这里只增加了两个限制
jobli.LimitFlags =
JOB_OBJECT_LIMIT_PRIORITY_CLASS |
JOB_OBJECT_LIMIT_JOB_TIME;
SetInformationJobObject(hJob, JobObjectBasicLimitInformation,
&jobli, sizeof(jobli));
//其次,设置UI限制
JOBOBJECT_BASIC_UI_RESTRICTIONS jobuir;
jobuir.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE;//初始化为0
//进程不能访问用户对象(比如窗口句柄)
jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
//进程不能关闭系统
jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;
SetInformationJobObject(hJob, JobObjectBasicUIRestrictions, &jobuir, sizeof(jobuir));
//创建子进程并加入作业对象中
//Note:进程被创建后,其线程要立刻挂起。再加入作业对象前,不能指向任何代码
//这里作业对象的要求,否则,进程指向的那部分代码可能就不受作业对象的限制
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
TCHAR szCmdLine[8];
_tcscpy_s(szCmdLine, _countof(szCmdLine), TEXT("CMD"));
BOOL bResult = CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE,
CREATE_SUSPENDED | CREATE_NEW_CONSOLE,
NULL, NULL, &si, &pi);
//将子进程加入到作业对象中
//注意:当创建子进程时,子进程会自动加入到父进程所父的作业对象中
AssignProcessToJobObject(hJob, pi.hProcess);
//限制可以回复子进程的主线程,开始执行代码
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
//枚举作业对象中的进程ID
EnumProcessIdsInJob(hJob);
//等待子进程结束或者作业对象所分配的cpu时间被用完
HANDLE h[2];
h[0] = pi.hProcess;
h[1] = hJob;
DWORD dw = WaitForMultipleObjects(2, h, FALSE, INFINITE);
switch (dw - WAIT_OBJECT_0)
{
case 0:
_tprintf(_T("The process has terminated...\n"));
break;
case 1:
_tprintf(_T("All of the job's allotted CPU time was used...\n"));
break;
}
FILETIME CreationTime;
FILETIME ExitTime;
FILETIME KernelTime;
FILETIME UserTime;
TCHAR szInfo[MAX_PATH];
GetProcessTimes(pi.hProcess, &CreationTime, &ExitTime,
&KernelTime, &UserTime);
StringCchPrintf(szInfo, _countof(szInfo),
TEXT("Kernel = %u|User = %u\n"),
KernelTime.dwLowDateTime / 10000,
UserTime.dwLowDateTime / 10000);
CloseHandle(pi.hProcess);
CloseHandle(hJob);
_tprintf(szInfo);
_tsystem(_T("pause"));
return;
}
演示完毕,大家可以上机实验