1.什么是作业
可以把作业看作是进程的容器,一个作业由一个或多个进程组成。作业可以对在其内的进程进行控制或限制进程的某些行为。
如果一个进程被加载到作业中,那么该进程的子进程也会自动被加载到该作业中。
用CloseHandle()关闭作业对象,只会把作业对象标记为Deletion,并不会终结作业内的所有进程。
只有当作业中的所进程都结束后系统才会释放作业对象所占用的资源。
2. 创建好一个作业之后,接着一般需要限制作业中的进程能做的事情;换言之,现在要设置 一个“沙箱”。
可以通过调用以下代码向作业应用限制:
对作业中的进程进行限制:
BOOL SetInformationJobObject(
HANDLE hJob,
JOBOBJECTINFOCLASS JobObjectInformationClass,
PVOID pJobObjectInformation,
DWORD cbJobObjectInformationSize);
第一个参数指定要限制的作业。第二个参数是一个枚举类型,指定了要应用的限制的类型。第
三个参数是一个数据结构的地址,数据结构中包含了具体的限制设置。第四个参数指出此数据
结构的大小(用于版本控制)。
![2010年10月13日 - fly - 天嗎荇箜](http://img.ph.126.net/vTjvyjO_ugk4CKT71MZalw==/3343078298393236121.png)
前两种可以限制进程占用过多的系统资源:如可以限制每个进程的运行时间或作业的运行时间。
第三种可以限制进程做关机,重启,切换用户的功能或能否读取剪切板听信息。
最后一种可以限制进程读取系统中的安全资源。
3.作业通知
1. 当作业中的进程发生某些特定事件时 作业会向外界发送通知。
如当作业中的某个进程或全部进程终止或有新的子进程产生时作业会向外界发送通知。我们可以通过以下两个函数来获取通知的内容。
QueryInformationJobObject
GetQueuedCompletionStatus
4.常用函数
QueryInformationJobObject() 查询统计信息
IsProcessInJob()
SetInformationJobObject()
AssignProcessToJobObject()
TerminateJobObject() //To kill all the processes within a job 终止作业
1. Job(作业),也就是进程组的概念,添加进同一个作业的进程能够通过作业内核对象来集中控制,设置一些额外的属性等。添加进一个作业就不能再移出。
2. IsProcessInJob、CreateJobObject、OpenJobObject。
3. 作业内核对象在它内部的所有进程都结束后才会被销毁。
4. 细节:当客户的作业句柄变量都被关闭后,即使作业对象还存在(因为进程没有全部结束),也不能再通过作业名打开作业再操作了。
5. Vista以上,通过任务管理器创建的进程,都被添加进了一个独立的作业;从命令行(cmd)创建的进程则不然。
6. 能够对作业添加的限制:基本限制(限制进程时间、优先级、物理内存占用等)、扩展限制(基础限制之上,还能限制内存使用总量,以及查看峰值内存使用)、UI限制(限制关机/重启、访问剪切板、切换桌面、改变显示器设置、访问作业外进程的句柄等)、安全限制 安全限制一旦设置,则不能修改 SetInformationJobObject、QueryInformationJobObject用于设置和查询限制。
7. AssignProcessToJobObject添加进程到作业。
8. 父进程位于某一作业中,子进程创建后也自动加入同一作业。除非作业的基本限制中包含JOB_OBJECT_LIMIT_BREAKAWAY_OK(允许进程时脱离作业),并且CreateProcess时指定CREATE_BREAKAWAY_FROM_JOB标记。
9. TerminateJobObject强制结束作业,同时结束作业内所有进程(等价于对作业内每个进程调TerminateProcess)。
10. QueryInformationJobObject除了查看作业限制外,也可以查看作业信息,包括总进程数、活跃进程数、总时间、总IO次数、进程ID列表等。
11. 作业结束后(所有内部进程结束),内核对象处于激活态,WaitForSingleObject返回。
12. 作业通知机制:将作业对象和IO完成端口绑定,作业中的事件(进程结束、时间到期、内存达到限制等)将通过完成端口事件来通知。
例程:
#include <iostream>
#include <string>
#include <windows.h>
#include <tchar.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
BOOL bInJob;
IsProcessInJob(GetCurrentProcess(), NULL, &bInJob); //询问一下当前进程是否已在作业中
if(bInJob)
{
wcout << TEXT("currecnt process is already in Job!") << endl;
system("PAUSE"); //“pause”这个系统命令的功能很简单,就是在命令行上输出一行类似于“Press any key to exit”的字,等 //待用 户按一 个键,然后返回。
return 0;
}
//为作业设一些安全限制,可设置的条件相当之多和复杂
JOBOBJECT_BASIC_LIMIT_INFORMATION jbli = {0};
jbli.PriorityClass = IDLE_PRIORITY_CLASS;
jbli.PerJobUserTimeLimit.QuadPart = 1000;
JOBOBJECT_BASIC_UI_RESTRICTIONS jbur;
jbur.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE|
JOB_OBJECT_UILIMIT_EXITWINDOWS | JOB_OBJECT_UILIMIT_HANDLES;
//创建一个作业
HANDLE hJob = CreateJobObject(NULL, TEXT("SomeJob"));
//把安全限制和作业关联起来
SetInformationJobObject(hJob, JobObjectBasicLimitInformation, &jbli, sizeof(jbli));
SetInformationJobObject(hJob, JobObjectBasicUIRestrictions, &jbur, sizeof(jbur));
//创建进程,并把之加入作业中
STARTUPINFO si = {sizeof(si)}; //指定新进程的主窗口特性
PROCESS_INFORMATION pi; //返回有关新进程及其主线程的信息
TCHAR cmd[] = TEXT("NOTEPAD");
if( CreateProcess(NULL, cmd, NULL, NULL, FALSE,
CREATE_SUSPENDED | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi) )
{
AssignProcessToJobObject(hJob, pi.hProcess); //把进程加入作业
ResumeThread(pi.hThread); //你需要恢复线程的句柄使用该函数能够激活线程的运行,使CPU分配资源让线程恢复运行
// 该函数和SuspendThread(hthread),线程挂起函数对应消耗线程挂起的时间计数,直到时间计数为0,则激活线程
CloseHandle(pi.hThread); //关闭线程句柄
//等待作业或进程结束,再进行统计
HANDLE hdls[] = { pi.hProcess, hJob };
//WaitForMultipleObjects——》http://blog.sina.com.cn/s/blog_4ac0a0d30100epkb.html
DWORD dwCondition = WaitForMultipleObjects(sizeof(hdls) / sizeof(HANDLE), hdls, FALSE, INFINITE);
switch(dwCondition - WAIT_OBJECT_0) //内核对象处于已通知状态,则该函数立即返回WAIT_OBJECT_0
{ //为FALSE,函数成功则返回值指明是哪个内核对象收到通知
case 0:
//do something here
break;
case 1:
//do something here
break;
}
FILETIME CreationTime, ExitTime, KernelTime, UserTime;
GetProcessTimes(pi.hProcess, &CreationTime, &ExitTime, &KernelTime, &UserTime); //获取与一个进程的经过时间有关的信息
wcout << TEXT("Kernel = ") << KernelTime.dwLowDateTime / 1000 << " and User = "
<< UserTime.dwLowDateTime / 10000 << endl;
CloseHandle(pi.hProcess); //关闭进程句柄
}
CloseHandle(hJob); //关闭作业
system("PAUSE");
return 0;
}