Skip to content

Instantly share code, notes, and snippets.

@xiongjia
Last active October 5, 2019 19:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xiongjia/a2ba02188674f74c489a to your computer and use it in GitHub Desktop.
Save xiongjia/a2ba02188674f74c489a to your computer and use it in GitHub Desktop.
The example of Windows Job Objects #devsample #win
# 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}")
/**
* 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>();
}
/**
* 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_) */
/**
* 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