Windows核心编程-作业
原文链接:http://zhujiangtao.com/?p=983
作业
- 作业
- 一个简单例程
- CreateJobObject 创建作业
- 作业限制和 SetInformationJobObject
- AssignProcessToJobObject 将进程添加到作业
- 终止作业
- QueryInformationJobObject 查询作业的统计信息
- 作业的通知消息
(1) 作业
[MSDN] 作业对象允许一组进程被当做一个单元进行管理。作业对象是可命名的、安全的、共享的对象,它能够控制它包含的所有进程的属性。执行在作业上的操作会影响作业包含的所有进程。
作业可视为进程的容器,可以对其中的所有进程加上限制条件。
使用CrateJobObject函数,创建一个作业
使用SetInformationJobObject函数,为作业添加限制条件
使用AssignProcessToJobObject函数,将进程添加到作业
使用IsProcessInJob函数,判断一个进程是否属于一个作业。
(2) 一个简单例程
#include <windows.h>
#include <tchar.h> int WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE,PWSTR lpCmdLine,int nShowCmd){ //创建一个作业内核对象
HANDLE hJob = CreateJobObject(NULL,NULL); // ////////////////////////////////////////////////////////////
//为作业添加一些基本限制 //基本限制结构体
JOBOBJECT_BASIC_LIMIT_INFORMATION jobli = {}; //作业的优先级
jobli.PriorityClass = IDLE_PRIORITY_CLASS; // //作业的CPU时间限制
jobli.PerJobUserTimeLimit.QuadPart = ; //1秒,单位是100纳秒 //指明限制条件
jobli.LimitFlags = JOB_OBJECT_LIMIT_PRIORITY_CLASS|JOB_OBJECT_LIMIT_JOB_TIME; //设定作业限制
SetInformationJobObject(hJob,JobObjectBasicLimitInformation,&jobli,sizeof(jobli)); ////////////////////////////////////////////////////////////
//为作业添加一些基本UI限制 //基本UI限制结构体
JOBOBJECT_BASIC_UI_RESTRICTIONS jobuir; //初始无限制
jobuir.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE; // //增加限制:作业(进程)不能注销操作系统
jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS; //增加限制:作业(进程)不能访问 系统的用户对象(如其他窗口)
jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES; //设定作业限制
SetInformationJobObject(hJob,JobObjectBasicUIRestrictions,&jobuir,sizeof(jobuir)); ////////////////////////////////////////////////////////////
//创建进程,并添加到作业中。进程初始化时必须是挂起状态,保证在添加到作业前不会执行任何代码 //创建进程
STARTUPINFO si={sizeof(si)};
PROCESS_INFORMATION pi;
CreateProcess(_T("C:\\Windows\\System32\\cmd.exe"),NULL,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&si,&pi); //CREATE_SUSPENDED //将进程添加到作业
AssignProcessToJobObject(hJob,pi.hProcess); //唤醒进程(的主线程)
ResumeThread(pi.hThread); //关闭句柄
CloseHandle(pi.hThread); ////////////////////////////////////////////////////////////
//等待进程结束或作业CPU时间耗完
HANDLE h[];
h[] = pi.hProcess;
h[] = hJob; DWORD ret = WaitForMultipleObjects(,h,FALSE,INFINITE);
switch(ret-WAIT_OBJECT_0){
case :
//进程结束
MessageBox(NULL,_T("进程结束"),_T("提示"),MB_OK);
break;
case :
//作业分配的CPU时间耗完
MessageBox(NULL,_T("时间耗尽"),_T("提示"),MB_OK);
break;
} //关闭句柄
CloseHandle(pi.hProcess);
CloseHandle(hJob); return ;
}
(3) CreateJobObject 创建作业
HANDLE
WINAPI CreateJobObject(
//创建作业内核对象
__in_opt LPSECURITY_ATTRIBUTES lpJobAttributes,
//安全结构体
__in_opt
LPCTSTR
lpName
//名称,可以为NULl
);
(4)作业限制 和 SetInformationJobObject
作业限制类型有:基本限制、扩展限制、UI限制、安全性限制
使用SetInformationJobObject可以为作业指定限制。
BOOL WINAPI SetInformationJobObject( //设置作业限制
__in HANDLE hJob, //要添加限制的作业
__in JOBOBJECTINFOCLASS JobObjectInfoClass, //限制的类型
__in LPVOID lpJobObjectInfo, //限制的值
__in DWORD cbJobObjectInfoLength //限制的值的长度
);
限制类型
|
说明
|
第二个参数的值
|
第三个参数的结构
|
基本限制
|
CPU分配限制
|
JobObjectBasicLimitInformation
|
JOBOBJECT_BASIC_LIMIT_INFORMATION
|
扩展限制
|
基本限制+内存分配限制 |
JobObjectExtendedLimitInformation
|
JOBOBJECT_EXTENDED_LIMIT_INFORMATION
|
基本UI限制
|
防止作业中进程改变UI |
JobObjectBasicUIRestictions
|
JOBOBJECT_BASIC_UI_RESTRICTIONS
|
安全性限制
|
防止作业中进程访问保密资源 |
JobObjectSecurityLimitInformation
|
JOBOBJECT_SECURITY_LIMIT_INFORMATION
|
[1] 基本限制
//基本限制:CPU限制
typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION {
LARGE_INTEGER PerProcessUserTimeLimit; //如果LimitFlags含有JOB_OBJECT_LIMIT_PROCESS_TIME,则此参数表示分配给每个进程的用户模式执行时间,单位100ns.超时进程会被终止
LARGE_INTEGER PerJobUserTimeLimit; //如果LimitFlags含有JOB_OBJECT_LIMIT_JOB_TIME,则此参数表示分配给作业的用户模式执行时间,超时作业会被终止
DWORD LimitFlags; //指明哪些限制对作业有效
SIZE_T MinimumWorkingSetSize; //如果LimitFlags含有JOB_OBJECT_LIMIT_WORKINGSET,则此参数表示作业中每个进程的最小工作集大小
SIZE_T MaximumWorkingSetSize; //同上,最大工作集大小
DWORD ActiveProcessLimit; //如果LimitFlags含有JOB_OBJECT_LIMIT_ACTIVE_PROCESS,则此参数表示作业中可以同时运行的最大进程数量
ULONG_PTR Affinity; //如果LimitFlags含有JOB_OBJECT_LIMIT_AFFINITY,则此参数表示能够运行的进程的CPU子集
DWORD PriorityClass; //如果LimitFlags含有JOB_OBJECT_LIMIT_PRIORITY_CLASS,则此参数表示作业中所有进程的优先级
DWORD SchedulingClass; //如果LimitFlags含有JOB_OBJECT_LIMIT_SCHEDULING_CLASS,则此参数表示相同优先级的作业的调度优先级(0-9,默认5),值越大,CPU时间越长
} JOBOBJECT_BASIC_LIMIT_INFORMATION, *PJOBOBJECT_BASIC_LIMIT_INFORMATION;
[2] 扩展限制
//扩展限制:基本限制+内存限制
typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION {
JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; //基本限制
IO_COUNTERS IoInfo; //保留不用。IO计数器
SIZE_T ProcessMemoryLimit; //每个进程能使用的内存量(“基本限制”参数的LimitFlags需含有JOB_OBJECT_LIMIT_PROCESS_MEMORY)
SIZE_T JobMemoryLimit; //作业(所有进程)能使用的内存量(“基本限制”参数的LimitFlags需含有JOB_OBJECT_LIMIT_JOB_MEMORY )
SIZE_T PeakProcessMemoryUsed; //只读。单个进程需要使用的内存最大值
SIZE_T PeakJobMemoryUsed; //只读。作业需要使用的内存最大值
} JOBOBJECT_EXTENDED_LIMIT_INFORMATION, *PJOBOBJECT_EXTENDED_LIMIT_INFORMATION;
[3] 基本UI限制
//基本UI限制
typedef struct _JOBOBJECT_BASIC_UI_RESTRICTIONS {
DWORD UIRestrictionsClass; //下表标志中一个或是组合
} JOBOBJECT_BASIC_UI_RESTRICTIONS, *PJOBOBJECT_BASIC_UI_RESTRICTIONS;
值 |
说明
|
JOB_OBJECT_UILIMIT_EXITWINDOWS
|
防止进程通过ExitWindowsEx函数退出、关闭、重启或关闭系统电源
|
JOB_OBJECT_UILIMIT_READCLIPBOARD
|
防止进程读取剪切板的内容
|
JOB_OBJECT_UILIMIT_WRITECLIPBOARD | 防止进程写剪切板内容 |
JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS |
防止进程通过SystemParametersInfor函数来改变系统参数
|
JOB_OBJECT_UILIMIT_DISPLAYSETTINGS
|
防止进程通过ChangeDisplaySettings函数来改变显示设置
|
JOB_OBJECT_UILIMIT_GLOBALATOMS
|
防止进程访问全局的基本结构表,为作业分配自己的基本结构表,作业中进程只能访问该表。 |
JOB_OBJECT_UILIMIT_DESKTOP
|
防止进程使用CreateDesktop或SwitchDesktop函数创建或转换桌面 |
JOB_OBJECT_UILIMIT_HANDLES
|
防止进程使用作业外部的进程创建的用户对象的句柄(如HWND) |
[4] 安全性限制
Windows XP(不包括XP)之后的系统不再支持该限制,需要为每个进程单独指定安全设置。
(5)AssignProcessToJobObject 将进程添加到作业
要添加到作业的进程在创建时,需使用CREATE_SUSPEND标志,防止加入作业前进程执行任何代码。
BOOL WINAPI AssignProcessToJobObject( __in HANDLE hJob, //作业句柄
__in HANDLE hProcess //进程句柄
);
一个进程加入到一个作业后,不能再转到另一个作业。
作业中的进程生成的新进程会自动成为作业的一部分。可以通过下面两种方法改变这种特性:
[1] 打开JOBOBJECT_BASIC_LIMIT_INFROMATION 的LimitFlags成员的JOB_OBJECT_BREAKAWAY_OK标志,告诉系统,新生成的进程可以在作业外部运行。同时使用CREATE_BREAKAWAY_FROM_JOB 标志调用CreateProcess创建新进程
[2] 打开JOBOBJECT_BASIC_LIMIT_INFROMATION 的LimitFlags成员的JOB_OBJECT_SILENT_BREAKAWAY_OK标志,告诉系统,新生成的进程可以在作业外部运行。
(6) 终止作业
BOOL WINAPI TerminateJobObject(
__in HANDLE hJob, //作业
__in UINT uExitCode //退出码。作业中所有进程的退出码自动设为uExitCode
);
(7) QueryInformationJobObject 查询作业的统计信息
(8) 作业的通知消息
创建一个IO完成端口(IO Completion Port)内核对象,然后将作业对象或多个作业对象与完成端口关联起来(使用SetInformationJobObject函数),然后让一个或多个线程在完成端口上等待作业通知的到来。
#include <windows.h>
#include <process.h> //_beginthreadex
#include <tchar.h> #define CMPKEY_JOBOBJECT 1
#define CMPKEY_TERMINATE 2 typedef unsigned (__stdcall *PTHREAD_START) (void *); //IO完成端口监听线程回调函数
DWORD WINAPI JobNotify(LPVOID lpParam)
{
HANDLE hIOCP = (HANDLE)lpParam; while (TRUE)
{
DWORD dwBytesTransferred;
ULONG_PTR CompKey;
LPOVERLAPPED po; //从IO完成端口中获取一个消息
GetQueuedCompletionStatus(hIOCP,&dwBytesTransferred,&CompKey,&po,INFINITE); //退出消息
if (CompKey == CMPKEY_TERMINATE)
{
MessageBox(NULL,_T("监听线程退出"),_T("提示"),MB_OK);
break;
} //来自作业对象hJob的消息
if(CompKey == CMPKEY_JOBOBJECT)
{
MessageBox(NULL,_T("收到来自作业的消息"),_T("提示"),MB_OK); switch(dwBytesTransferred){
case JOB_OBJECT_MSG_END_OF_JOB_TIME:
MessageBox(NULL,_T("作业限制时间耗尽"),_T("提示"),MB_OK);
break;
case JOB_OBJECT_MSG_END_OF_PROCESS_TIME:
{
TCHAR szProcessName[MAX_PATH];
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,(DWORD)po); if(hProcess == NULL){
_stprintf(szProcessName,_T("%s"),_T("未知进程名"));
}
else{
DWORD dwSize = (DWORD)MAX_PATH;
QueryFullProcessImageName(hProcess,,szProcessName,&dwSize);
CloseHandle(hProcess);
} TCHAR info[MAX_PATH];
_stprintf(info,_T("进程%s(ID=%d)限制时间耗尽 "),szProcessName,po); MessageBox(NULL,info,_T("提示"),MB_OK);
}
break;
case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT:
MessageBox(NULL,_T("运行的进程超过限制"),_T("提示"),MB_OK);
break;
case JOB_OBJECT_MSG_NEW_PROCESS:
MessageBox(NULL,_T("作业中产生新进程"),_T("提示"),MB_OK);
break;
case JOB_OBJECT_MSG_EXIT_PROCESS: {
TCHAR szProcessName[MAX_PATH];
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,(DWORD)po); if(hProcess == NULL){
_stprintf(szProcessName,_T("%s"),_T("未知进程名"));
}
else{
DWORD dwSize = (DWORD)MAX_PATH;
QueryFullProcessImageName(hProcess,,szProcessName,&dwSize);
CloseHandle(hProcess);
} TCHAR info[MAX_PATH];
_stprintf(info,_T("进程%s(ID=%d)终止 "),szProcessName,po); MessageBox(NULL,info,_T("提示"),MB_OK);
}
break;
}
}
}
return ;
} int WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE,PWSTR lpCmdLine,int nShowCmd){ //创建一个作业内核对象
HANDLE hJob = CreateJobObject(NULL,NULL); // //创建一个IO完成端口
HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,,); //创建一个线程监听IO完成端口通知消息
HANDLE hThreadIOCP = (HANDLE)_beginthreadex(NULL,,(PTHREAD_START)JobNotify,(LPVOID)hIOCP,,NULL); //将IO完成端口与作业关联
JOBOBJECT_ASSOCIATE_COMPLETION_PORT jobacp;
jobacp.CompletionKey = (PVOID)CMPKEY_JOBOBJECT; //任意一个全局唯一的值
jobacp.CompletionPort = hIOCP; //IO完成端口句柄
SetInformationJobObject(hJob,JobObjectAssociateCompletionPortInformation,&jobacp,sizeof(jobacp)); //关联 ////////////////////////////////////////////////////////////
//创建进程,并添加到作业中。进程初始化时必须是挂起状态,保证在添加到作业前不会执行任何代码 STARTUPINFO si={sizeof(si)};
PROCESS_INFORMATION pi;
CreateProcess(_T("C:\\Windows\\System32\\cmd.exe"),NULL,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&si,&pi); //CREATE_SUSPENDED
AssignProcessToJobObject(hJob,pi.hProcess);//将进程添加到作业
MessageBox(NULL,_T(""),_T("Tips"),MB_OK);
ResumeThread(pi.hThread);//唤醒进程(的主线程)
CloseHandle(pi.hThread); //关闭句柄
CloseHandle(pi.hProcess);
MessageBox(NULL,_T("MESSAGE"),_T("Tips"),MB_OK); //发送一条消息给IO完成端口,结束IO完成端口线程
PostQueuedCompletionStatus(hIOCP,,CMPKEY_TERMINATE,NULL); //等待IO完成端口线程终止
WaitForSingleObject(hThreadIOCP,INFINITE); //关闭句柄
CloseHandle(hIOCP);
CloseHandle(hThreadIOCP);
CloseHandle(hJob);
return ;
}
Windows核心编程-作业的更多相关文章
- Windows核心编程&作业
1. 作业内核对象 允许将进程组合在一起并创建一个"沙箱"来限制进程能够做什么.我们可以将作业内核对象想象成一个进程容器(即使只有一个进程也具有相当的重要性) 限制包括可以分配的最 ...
- windows核心编程---第八章 使用内核对象进行线程同步
使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...
- 回忆读windows 核心编程
看<windows 核心编程> 第五版到纤程了,下一章节即将介绍内存体系编程.如果做window平台下的开发,我感觉此书一定要读.记得开始讲解了window的基础,然后讲解内核对象.内核对 ...
- 《Windows核心编程》第5版 学习进度备忘
学习资源:<Windows核心编程>第5版 知识基础支持: 本书与<Windows程序设计>第5版珍藏版结合很好,二者重叠内容不多,二者互补性强,而且相关方面的优秀书籍 跳过的 ...
- 【windows核心编程】 第六章 线程基础
Windows核心编程 第六章 线程基础 欢迎转载 转载请注明出处:http://www.cnblogs.com/cuish/p/3145214.html 1. 线程的组成 ① 一个是线程的内核 ...
- 《Windows核心编程》读书笔记 上
[C++]<Windows核心编程>读书笔记 这篇笔记是我在读<Windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的思考和对 ...
- 【Windows】windows核心编程整理(上)
小续 这是我11年看<windows核心编程>时所作的一些笔记,现整理出来共享给大家 windows核心编程整理(上) windows核心编程整理(下) 线程的基础知识 进程是不活泼的,进 ...
- C++Windows核心编程读书笔记
转自:http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E6%96%87/71405.shtml "C++Windows核心编程读书笔 ...
- 【转】《windows核心编程》读书笔记
这篇笔记是我在读<Windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的思考和对实现的推断,因此不少条款和Windows实际机制可能有出入 ...
随机推荐
- 转 JDBC连接数据库(二)——连接池
https://www.cnblogs.com/xiaotiaosi/p/6398371.html 数据库保持长连接,不过一直都是idle,除非有用户激活连接,这样后果是无法删除用户,但是不影响数据库 ...
- 转——jdbcType与javaType的对应关系
------------------------------------------------ 原文:https://blog.csdn.net/haofeng82/article/details/ ...
- Appium自动化中截图的问题
在用Appium做UI自动化过程中,大家会发现测试报告很重要,而在测试报告中截图很重要. 因为很多公司都是用Jenkins作为持续集成工具,所以要让执行自动化测试的人看明白自动化在跑什么,哪里失败了, ...
- 使用Advanced Installer进行二次打包
使用Advanced Installer进行二次打包 在上一篇使用InstallerShield打包VS程序中,我已经叙述过,为什么要进行二次打包的问题,在此我就不再赘述.本次长枪直入,说一说如何使用 ...
- 乐蜂网SALES倒计时原码展示
这是一个基于jquey写的倒计时.当然代码有点小改动,只是改了一下展示效果. 在静态页添加显示倒计时的容器,并引用下面脚本,代入时间参数即可使用. timeoutDate——到期时间,时间格式为201 ...
- 7.vs的基本设置
1.运行代码的两种方式 (1) 按F5 (2)点击快速菜单栏上面的绿色三角形按钮. 2.生成解决方案 F6. 3.在代码上看见红色的波浪线,表示代码有语法错误. 4.一般我们在运行一个程序之前,我们先 ...
- Html+CSS--->第一周初探
html css 学了一周的前端,谈谈我的感想 我一直在使用sublime text 3来编辑我的代码,其中有很多很好用的快捷键和插件大大提高了我的开发效率 在这里我极力推荐使用编辑器来进行学习前端. ...
- python面试题——框架和其他(132题)
一.框架对比 (1)django.flask.tornado框架的比较? Django:简单的说Django是一个大而全的Web框架,内置了很多组件,ORM.admin.Form. ModelForm ...
- JavaScript写入文件到本地
工作中有时需要通过 JavaScript 保存文件到本地,我们都知道 JavaScript 基于安全的考虑,是不允许直接操作本地文件的.IE 可以通过 VB 插件的方式进行,而 Chrome 和 fi ...
- 分布式系统ID生成方案汇总
在分布式系统中,需要对大量的数据.消息.请求等进行唯一的标识,例如分布式数据库的ID需要满足唯一且多数据库同步,在单一系统中,使用数据库自增主键可以满足需求,但是在分布式系统中就需要一个能够生成全局唯 ...