概述
- Boost.Process提供了管理当前执行进程上下文、创建子进程、用C++ 流和异步I/O进行通信的能力。
- 由于我希望对外屏蔽掉boost库的引用并做简化封装,因此有了如下进程管理库的封装。
- 该封装支持windows和linux平台,支持x86和ARM。
完整Cpp代码如下
#pragma once
#include <chrono>
#include <stdint.h>
#include <algorithm>
#include <boost/process.hpp>
#include <boost/process/extend.hpp>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <string>
#if defined(BOOST_WINDOWS_API)
#include <boost/locale.hpp>
#include <TlHelp32.h>
#elif defined(BOOST_POSIX_API)
#include <sys/types.h>
#include <signal.h>
#endif
namespace ProcessHelper
{
static uint64_t getTimeStamp()
{
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
return ms.count();
}
static uint32_t getCurrentProcessId()
{
#ifdef _WIN32
return GetCurrentProcessId();
#else
return ::getpid();
#endif
}
static std::string getProcessRunningTime(uint64_t startTimeStamp)
{
auto now = getTimeStamp();
auto diff = now - startTimeStamp;
auto min = double(diff) / (1000 * 60);
return std::to_string(min);
}
#if defined(BOOST_WINDOWS_API)
static int isRunning(int pid)
{
HANDLE pss = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
PROCESSENTRY32 pe = {
0};
pe.dwSize = sizeof(pe);
if (Process32First(pss, &pe))
{
do
{
if (pe.th32ProcessID == pid)
return 0;
} while (Process32Next(pss, &pe));
}
CloseHandle(pss);
return -1;
}
#elif defined(BOOST_POSIX_API)
static int isRunning(int pid)
{
if (0 == kill(pid, 0))
{
std::string path = std::string("/proc/") + std::to_string(pid) + "/status";
std::ifstream fs;
fs.open(path);
if (!fs)
return -1;
std::string line;
while (getline(fs, line))
{
std::size_t found = line.find("State:");
if (found == std::string::npos)
continue;
else
{
found = line.find("zombie");
if (found == std::string::npos)
return 0;
else
return -2;
}
}
}
else
return -1;
}
#endif
static std::tuple<bool, std::string> killChildProcess(int pid)
{
std::string err;
bool ret = false;
try
{
auto id = boost::process::pid_t(pid);
boost::process::child pros(id);
std::error_code ec;
pros.terminate(ec);
if (ec.value() == 0)
return std::make_tuple(true, err);
}
catch (boost::process::process_error &exc)
{
err = exc.what();
}
return std::make_tuple(false, err);
}
static std::tuple<bool, std::string> killProcess(int pid, bool isChild = true)
{
std::string err;
bool ret = false;
#if defined(BOOST_WINDOWS_API)
return killChildProcess(pid);
#elif defined(BOOST_POSIX_API)
if (isChild)
return killChildProcess(pid);
else
{
std::string cmd("kill -9 ");
cmd += std::to_string(pid);
auto ret = boost::process::system(cmd);
if (ret == 0)
return std::make_tuple(true, err);
}
return std::make_tuple(false, err);
#endif
}
static std::tuple<std::vector<int>, std::string> getAllProcessPidsByName(const std::string &processName)
{
std::vector<int> pids;
std::string err;
try
{
#if defined(BOOST_WINDOWS_API)
std::wstring wName;
std::string exe(".exe");
wName = boost::locale::conv::to_utf<wchar_t>(processName + exe, "GBK");
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32W entry;
entry.dwSize = sizeof entry;
if (!Process32FirstW(hSnapShot, &entry))
{
return std::make_tuple(std::move(pids), err);
}
do
{
if (std::wstring(entry.szExeFile) == wName)
{
pids.emplace_back(entry.th32ProcessID);
}
} while (Process32NextW(hSnapShot, &entry));
#elif defined(BOOST_POSIX_API)
boost::filesystem::path path = "/proc";
boost::filesystem::directory_iterator end;
for (boost::filesystem::directory_iterator iter(path); iter != end; iter++)
{
boost::filesystem::path p = *iter;
std::ifstream statusFile;
statusFile.open(p.string() + std::string("/status"));
if (!statusFile)
continue;
std::string statusContent;
getline(statusFile, statusContent);
std::vector<std::string> a;
boost::algorithm::split(a, statusContent, boost::algorithm::is_any_of(":"), boost::algorithm::token_compress_on);
if (boost::algorithm::trim_copy(a[1]) == processName)
{
pids.push_back(std::stoi(p.leaf().string()));
}
statusFile.close();
statusFile.clear();
}
#endif
}
catch (boost::process::process_error &exc)
{
err = exc.what();
}
return std::make_tuple(std::move(pids), err);
}
static std::tuple<int, std::string> startProcess(const std::string &processName, const std::string &processArgv)
{
int pid = -1;
std::string err;
try
{
#if defined(BOOST_WINDOWS_API)
auto p = processName + ".exe";
if (!boost::filesystem::exists(p))
{
p = boost::filesystem::current_path().string() + "/" + p;
if (!boost::filesystem::exists(p))
{
err = "process not exist";
return std::make_tuple(pid, err);
}
}
boost::process::child c(
p, processArgv, boost::process::extend::on_setup = [](auto &exec) {
exec.creation_flags |= boost::winapi::CREATE_NEW_CONSOLE_;
});
#elif defined(BOOST_POSIX_API)
auto p = processName;
p = boost::filesystem::current_path().string() + "/" + p;
if (!boost::filesystem::exists(p))
{
err = "process not exist";
return std::make_tuple(pid, err);
}
p = p + " " + processArgv;
boost::process::child c(p);
#endif
pid = c.id();
c.detach();
}
catch (boost::process::process_error &exc)
{
err = exc.what();
pid = -1;
}
return std::make_tuple(pid, err);
}
}
测试代码
#include "processhelper.hpp"
using namespace ProcessHelper;
int main()
{
std::string processArgv = "test.txt";
std::string processName = "notepad";
auto newtup = ProcessHelper::startProcess(processName, processArgv);
auto pid = std::get<0>(newtup);
if (0 != ProcessHelper::isRunning(pid))
{
std::cerr << "process " << pid << " is not running!" << std::endl;
return -1;
}
else
{
std::cout << "process " << pid << " is running!" << std::endl;
}
auto tup = ProcessHelper::getAllProcessPidsByName(processName);
auto pids = std::get<0>(tup);
for (auto pid : pids)
{
std::cout << "killing " << pid << std::endl;
ProcessHelper::killProcess(pid, false);
if (0 != ProcessHelper::isRunning(pid))
std::cout << "process " << pid << " killed!" << std::endl;
}
return 0;
}