zoukankan      html  css  js  c++  java
  • 作业通知

    一.作业(job)内核对象概念

    1.为什么要有作业job
    便于管理进程:进程的父子关系只存在于创建的子进程的那一刻,Windows并不一直维护着这种父子关系,这使得管理进程并不是件容易的事。
    2.作业的功能
    作业对象是用于将一组进程作为一个管理单元的内核对象,本质上可以理解为其实就是进程池对象,可将作业对象看作是进程的容器。
        作来对象可以用来限制一组进程的占用内存数量、占用CPU周期数、进程优先级等的一个“沙箱”。

       最终可以通过作业对象将该对象中的所有进程全部关闭(普通方法很难控制)

    3.作业通知
    通过结合一个完成端口对象并利用一个线程 实时动态的监控作业对象的执行(如得到一些消息,以便及时响应作业对象中的进程变化情况)
     

    二.作业对象的基本用法

      


      CreateJobObject (创建作业对象)
      IsProcessInJob (进程是否己经与某个作业对象关联)
      SetInformationJobObject (设置作业对象或进程的限制)
      AssignProcessToJobObject (将进程添加到作业中)
      QueryInformationJobObject (查询作业对象中施加的限制)
      TerminateJobObject ("杀死"作业中所有的进程)
      CloseHandle (关闭作业对象句柄,导致所有进程不能访问作业对象,但作业仍存在!)
      OpenJobObject (打开一个指定名称的作业对象句柄)

    三.作业通知实现

         

    1.创建作业和完成端口:

    //创建作业
    HANDLE JobHandle = CreateJobObject(
    NULL, //安全属性默认
    NULL); //匿名作业
    if (JobHandle == NULL)
    {
    goto Exit;
    }
    //创建一个完成端口
    __CompletionPortHandle = CreateIoCompletionPort(
    INVALID_HANDLE_VALUE, //关联的文件句柄
    NULL, //已经存在的完成端口
    0, //传送给处理函数的参数
    0); //有多少个线程在访问这个消息队列
    if (__CompletionPortHandle==NULL)
    {
    goto Exit;
    }


    2.作业与完成关联

    //作业与完成关联
    JOBOBJECT_ASSOCIATE_COMPLETION_PORT AssociateCompletePort;
    AssociateCompletePort.CompletionKey = (PVOID)JOB_OBJECT_COMPLETE_KEY;
    AssociateCompletePort.CompletionPort = __CompletionPortHandle;
    if (SetInformationJobObject(
    JobHandle, //作业句柄
    JobObjectAssociateCompletionPortInformation,
    &AssociateCompletePort,
    sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT)
    )==FALSE)
    {
    goto Exit;
    }


    3.设置限制:

    //UI限制
    JOBOBJECT_BASIC_UI_RESTRICTIONS Restrictions;

    Restrictions.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE; //初始化为0
    Restrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS; //进程不能访问用户对象(如窗口句柄)
    Restrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES; //进程不能关闭系统
    //设置限制
    SetInformationJobObject(
    JobHandle, //作业对象句柄
    JobObjectBasicUIRestrictions, //限制的类型,
    &Restrictions, //指向初始化过的结构体,包含具体的限制
    sizeof(JOBOBJECT_BASIC_UI_RESTRICTIONS)); //结构体的大小

    4.创建一个守候在完成端口上的线程

    //创建一个守候在完成端口上的线程,监视
    HANDLE ThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProcedure, NULL, 0, NULL);
    if (ThreadHandle == NULL)
    {
    goto Exit;
    }

    源代码:

    // 作业通知.cpp : 定义控制台应用程序的入口点。
    
    
    #include "stdafx.h"
    #include <windows.h>
    #include <iostream>
    using namespace std;
    
    #define  JOB_OBJECT_COMPLETE_KEY  100
    #define  EXIT_THREAD_COMPLETE_KEY 101
    DWORD WINAPI ThreadProcedure(LPVOID ParameterData);
    HANDLE __CompletionPortHandle = NULL;
    BOOL __IsLoop = TRUE;
    int main()
    {
        //创建作业
        HANDLE JobHandle = CreateJobObject(
            NULL,    //安全属性默认
            NULL);   //匿名作业
        if (JobHandle == NULL)
        {
            goto Exit;
        }
        //创建一个完成端口
        __CompletionPortHandle =  CreateIoCompletionPort(
            INVALID_HANDLE_VALUE,   //关联的文件句柄
            NULL,                   //已经存在的完成端口
            0,                      //传送给处理函数的参数
            0);                     //有多少个线程在访问这个消息队列
        if (__CompletionPortHandle==NULL)
        {
            goto Exit;
        }
        //作业与完成关联
        JOBOBJECT_ASSOCIATE_COMPLETION_PORT AssociateCompletePort;
        AssociateCompletePort.CompletionKey = (PVOID)JOB_OBJECT_COMPLETE_KEY;
        AssociateCompletePort.CompletionPort = __CompletionPortHandle;
        if (SetInformationJobObject(
            JobHandle,                                    //作业句柄
            JobObjectAssociateCompletionPortInformation,  
            &AssociateCompletePort,                       
            sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT)   
            )==FALSE)
        {
            goto Exit;
        }
    
    
        //UI限制
        JOBOBJECT_BASIC_UI_RESTRICTIONS  Restrictions;
    
        Restrictions.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE;         //初始化为0
        Restrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;    //进程不能访问用户对象(如窗口句柄)
        Restrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;        //进程不能关闭系统
        //设置限制
        SetInformationJobObject(
            JobHandle,                                //作业对象句柄
            JobObjectBasicUIRestrictions,             //限制的类型,  
            &Restrictions,                            //指向初始化过的结构体,包含具体的限制    
            sizeof(JOBOBJECT_BASIC_UI_RESTRICTIONS)); //结构体的大小
    
        //创建一个守候在完成端口上的线程,监视
        HANDLE ThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProcedure, NULL, 0, NULL);
        if (ThreadHandle == NULL)
        {
            goto Exit;
        }
    
        WCHAR v1;
        do
        {
            wprintf(L"1..Create Process In Job
    ");
            wprintf(L"2..Remove Process From Job
    ");
            wprintf(L"3..Query Restrictions
    ");
            wprintf(L"4..Exit
    ");
        
            wscanf(L" %c", &v1);
    
            switch (v1)
            {
            case '1':
            {
                STARTUPINFO StartupInfo;
                memset(&StartupInfo, 0, sizeof(STARTUPINFO));
                StartupInfo.cb = sizeof(STARTUPINFO);
    
                PROCESS_INFORMATION ProcessInfo;
                memset(&ProcessInfo, 0, sizeof(PROCESS_INFORMATION));
            
                WCHAR CommandLine[] = L"Notepad.exe";
                //创建进程,且传入CREATE_SUSPENDED标志,暂时挂起进程,避免进程逃离“沙箱”
                BOOL IsOk = CreateProcess(NULL,CommandLine, NULL, NULL,
                    FALSE, CREATE_SUSPENDED | CREATE_NEW_CONSOLE | CREATE_BREAKAWAY_FROM_JOB,
                    NULL, NULL, &StartupInfo, &ProcessInfo);
                //将进程放入作业中
                AssignProcessToJobObject(JobHandle, ProcessInfo.hProcess);
                //再调用ResumeThread ,使进程的线程可以在作业的限制下执行代码
                ResumeThread(ProcessInfo.hThread);
                CloseHandle(ProcessInfo.hThread);
                CloseHandle(ProcessInfo.hProcess);
                break;
            }
    
            case '2':
            {
                TerminateJobObject(JobHandle, 0);   //终止作业中的所有进程 
                break;
            }
            case '4':
            {
                //发送自定义事件,触发GetQueuedCompletionStatus函数来取得数据包
                PostQueuedCompletionStatus(
                    __CompletionPortHandle,            //完成端口对象
                    0,
                    EXIT_THREAD_COMPLETE_KEY,         //退出消息
                    NULL);  
                goto Exit;
            }
    
            case '3':
            {
                QueryInformationJobObject(JobHandle, JobObjectBasicUIRestrictions,
                    &Restrictions, sizeof(Restrictions), NULL);
                wprintf(L"%x
    ", Restrictions.UIRestrictionsClass);
    
            }
            }
    
            wprintf(L"Do You Want To Continue?
    ");
    
            wscanf(L" %c", &v1);
    
    
        } while (v1 == 'y' || v1 == 'Y');
    
    Exit:
        
        if (__CompletionPortHandle!=NULL)
        {
            CloseHandle(__CompletionPortHandle);
            __CompletionPortHandle = NULL;
        }
        if (JobHandle!=NULL)
        {
            CloseHandle(JobHandle);
            JobHandle = NULL;
        }
        if (ThreadHandle!=NULL)
        {
            WaitForSingleObject(ThreadHandle, INFINITE);
            CloseHandle(ThreadHandle);
            ThreadHandle = NULL;
        }
        printf("Input AnyKey To Exit
    ");
        getchar();
        return 0;
    }
    DWORD WINAPI ThreadProcedure(LPVOID ParameterData)
    {
        DWORD  TransferredDataLength = 0;
        ULONG_PTR CompletionKey = 0;
        LPOVERLAPPED Overlapped;
        BOOL IsOk = FALSE;
        while (__IsLoop)
        {
            IsOk = GetQueuedCompletionStatus(
                __CompletionPortHandle, 
                &TransferredDataLength, //返回一个事件的ID
                &CompletionKey,         //返回触发这个事件的对象的句柄,即作业对象的句柄
                &Overlapped,            //事件对应的详细信息(NULL)
                INFINITE);
            
            if (IsOk==TRUE)
            {
                if (CompletionKey == JOB_OBJECT_COMPLETE_KEY)
                {
                    switch (TransferredDataLength)
                    {
                        /*
                        事件类型:
                        JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS    进程异常退出
                        JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT        同时活动的进程数达到设置的上限
                        JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO        作业对象中没有活动的进程了
                        JOB_OBJECT_MSG_END_OF_JOB_TIME            作业对象的CPU周期耗尽
                        JOB_OBJECT_MSG_END_OF_PROCESS_TIME        进程的CPU周期耗尽
                        JOB_OBJECT_MSG_EXIT_PROCESS                进程正常退出
                        JOB_OBJECT_MSG_JOB_MEMORY_LIMIT            作业对象消耗内存达到上限
                        JOB_OBJECT_MSG_NEW_PROCESS                有新进程加入到作业对象中
                        JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT        进程消耗内存数达到上限
                        */
                    //作业通知
                    case JOB_OBJECT_MSG_NEW_PROCESS:
                    {
                        wprintf(L"New Process ID:%d In Job
    ", Overlapped);
    
                        break;
                    }
                    case JOB_OBJECT_MSG_EXIT_PROCESS:
                    {
                        wprintf(L"New Process ID:%d Out Job
    ", Overlapped);   //进程已经消亡
    
                        break;
                    }
                    case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO:
                    {
                        wprintf(L"Active Procss Is Zero
    ");
                    }
    
                    default:
                    {
                    }
                    }
                }
                else if (CompletionKey==EXIT_THREAD_COMPLETE_KEY)
                {
    
                    printf("EXIT_THREAD_COMPLETE_KEY
    ");
                    break;
                }
            }
            else
            {
                printf("CloseHandle(__CompletionPortHandle)
    ");
                break;
            }
    
    
        }
    
        printf("ThreadProcedure() Exit
    ");
        return 0;
    }
  • 相关阅读:
    javaScript 中的异步编程
    javaScript内存泄漏
    javaScript| 对象的拷贝
    javaScript 数组的拷贝
    javaScript 去除数组中的重复值
    解决js key中的时间间隔
    js未命题(杂记)
    js中斐波拉切数的三种写法;
    js闭包的七中形式
    Javascript学习日志(三):闭包
  • 原文地址:https://www.cnblogs.com/lsh123/p/7325135.html
Copyright © 2011-2022 走看看