Last active
October 5, 2019 19:52
-
-
Save xiongjia/a2ba02188674f74c489a to your computer and use it in GitHub Desktop.
The example of Windows Job Objects #devsample #win
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# CMake build script | |
cmake_minimum_required(VERSION 2.8) | |
# project name & version | |
project(JobObj) | |
# common settings (Boost libraries) | |
if (MSVC) | |
# Enable the static libraries on Windows | |
foreach (flag_var | |
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE | |
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO | |
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE | |
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO) | |
# update to the static version of the run time library | |
string(REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") | |
endforeach() | |
set(CMAKE_C_STANDARD_LIBRARIES "") | |
set(CMAKE_CXX_STANDARD_LIBRARIES "") | |
endif() | |
# enable boost static flag | |
unset(Boost_LIBRARIES) | |
set(Boost_USE_STATIC ON) | |
set(Boost_USE_STATIC_LIBS ON) | |
set(Boost_USE_MULTITHREADED ON) | |
set(Boost_USE_STATIC_RUNTIME ON) | |
# boost components | |
find_package(Boost REQUIRED COMPONENTS | |
program_options) | |
include_directories("${PROJECT_SOURCE_DIR}" | |
"${Boost_INCLUDE_DIRS}") | |
set(jobobj_dbg_libs | |
"${Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG}") | |
set(jobobj_opt_libs | |
"${Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE}") | |
add_executable(job_obj | |
"${PROJECT_SOURCE_DIR}/main.cxx" | |
"${PROJECT_SOURCE_DIR}/job_obj.hxx" | |
"${PROJECT_SOURCE_DIR}/job_obj.cxx") | |
target_link_libraries(job_obj | |
debug "${jobobj_dbg_libs}" | |
optimized "${jobobj_opt_libs}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The example of Windows Job Objects | |
*/ | |
#include "boost/make_shared.hpp" | |
#include "job_obj.hxx" | |
class JobObjImpl : public JobObj | |
{ | |
private: | |
HANDLE m_job; | |
public: | |
JobObjImpl(void) | |
: JobObj() | |
, m_job(NULL) | |
{ | |
m_job = CreateJobObject(NULL, NULL); | |
if (NULL == m_job) | |
{ | |
return; | |
} | |
/* > JOB_OBJECT_LIMIT_BREAKAWAY_OK & | |
* JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK: | |
* The child processes of the parent process are not | |
* associated with the job. | |
* | |
* > JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION: | |
* Forces a call to the SetErrorMode function with the | |
* SEM_NOGPFAULTERRORBOX flag for each process | |
* associated with the job. | |
* | |
* > JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE: | |
* Causes all processes associated with the job to | |
* terminate when the last handle to the job is closed. | |
*/ | |
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobELInfo = {0}; | |
jobELInfo.BasicLimitInformation.LimitFlags = | |
JOB_OBJECT_LIMIT_BREAKAWAY_OK| | |
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK| | |
JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION| | |
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; | |
BOOL ret = SetInformationJobObject(m_job, | |
JobObjectExtendedLimitInformation, &jobELInfo, sizeof(jobELInfo)); | |
if (!ret) | |
{ | |
CloseHandle(m_job); | |
m_job = NULL; | |
} | |
} | |
~JobObjImpl(void) | |
{ | |
if (NULL != m_job) | |
{ | |
CloseHandle(m_job); | |
m_job = NULL; | |
} | |
} | |
virtual bool Associate(HANDLE proc) | |
{ | |
if (NULL == m_job) | |
{ | |
return false; | |
} | |
/* A handle to the process to be tested. | |
* The handle must have the PROCESS_QUERY_INFORMATION or | |
* PROCESS_QUERY_LIMITED_INFORMATION access right. | |
*/ | |
BOOL inJob = FALSE; | |
BOOL ret = IsProcessInJob(m_job, proc, &inJob); | |
if (ret && inJob) | |
{ | |
/* don't need to associate it again */ | |
return true; | |
} | |
ret = AssignProcessToJobObject(m_job, proc); | |
return ret ? true : false; | |
} | |
}; | |
JobObj::JobObj(void) | |
{ | |
/* NOP */ | |
} | |
boost::shared_ptr<JobObj> JobObj::Create(void) | |
{ | |
return boost::make_shared<JobObjImpl>(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The example of Windows Job Objects | |
*/ | |
#ifndef _JOB_OBJ_H_ | |
#define _JOB_OBJ_H_ 1 | |
#include "boost/utility.hpp" | |
#include "boost/shared_ptr.hpp" | |
#include <Windows.h> | |
class JobObj : boost::noncopyable | |
{ | |
public: | |
static boost::shared_ptr<JobObj> Create(void); | |
virtual bool Associate(HANDLE proc) = 0; | |
protected: | |
JobObj(void); | |
}; | |
#endif /* !defined(_JOB_OBJ_H_) */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The example of Windows Job Objects | |
*/ | |
#include <iostream> | |
#include <string> | |
#include <vector> | |
#include "boost/utility.hpp" | |
#include "boost/foreach.hpp" | |
#include "boost/program_options.hpp" | |
#include <Windows.h> | |
#include "job_obj.hxx" | |
/* namespace alias */ | |
namespace po = boost::program_options; | |
static void create_child(const char *app, const unsigned int count) | |
{ | |
auto jobObj = JobObj::Create(); | |
std::vector<HANDLE> procHandles; | |
procHandles.resize(count); | |
for (unsigned int i = 0; i < count; ++i) | |
{ | |
STARTUPINFO startupInf = {0}; | |
startupInf.cb = sizeof(startupInf); | |
PROCESS_INFORMATION procInf = {0}; | |
BOOL ret = CreateProcess(app, NULL, NULL, NULL, FALSE, | |
0, NULL, NULL, &startupInf, &procInf); | |
if (!ret) | |
{ | |
std::cerr << "Cannot create process (" << app << | |
"). Last Error: " << GetLastError() << std::endl; | |
BOOST_FOREACH(HANDLE procHandle, procHandles) | |
{ | |
CloseHandle(procHandle); | |
} | |
return; | |
} | |
std::cout << "Created process (" << app << "). PID: " | |
<< procInf.dwProcessId << std::endl; | |
jobObj->Associate(procInf.hProcess); | |
procHandles[i] = procInf.hProcess; | |
CloseHandle(procInf.hThread); | |
} | |
/* Wait for all processes */ | |
WaitForMultipleObjects(procHandles.size(), | |
&procHandles[0], TRUE, INFINITE); | |
std::cout << "All processes have been termiated" << std::endl; | |
BOOST_FOREACH(HANDLE procHandle, procHandles) | |
{ | |
CloseHandle(procHandle); | |
} | |
} | |
int main(int argc, char **argv) | |
{ | |
po::options_description desc("MainOptions"); | |
desc.add_options() | |
("help,h", "Print help message") | |
("proc,p", | |
po::value<std::string>()->default_value("C:/Windows/notepad.exe"), | |
"The child process name. (Default value is notepad.exe)") | |
("count,c", | |
po::value<unsigned int>()->default_value(1), | |
"The number of the child process. (Default value is 1)"); | |
po::variables_map vm; | |
try | |
{ | |
po::store(po::parse_command_line(argc, argv, desc), vm); | |
} | |
catch (po::error &e) | |
{ | |
/* Invalid options */ | |
std::cerr << "ERROR: " << e.what() << std::endl << std::endl; | |
std::cout << "Windows Job Object tester:" << std::endl | |
<< desc << std::endl; | |
return 0; | |
} | |
if (vm.count("help")) | |
{ | |
/* print usage */ | |
std::cout << "Boost property_tree tester:" << std::endl | |
<< desc << std::endl; | |
return 0; | |
} | |
/* create child proc */ | |
unsigned int procCnt = vm["count"].as<unsigned int>(); | |
create_child(vm["proc"].as<std::string>().c_str(), | |
procCnt <= 0 ? 1 : procCnt); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment