C++基于boost.process封装的进程管理模块

概述

  • 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) // return minutes
    {
    
    
        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
            {
    
    
                // pe.szExeFile can also be useful
                if (pe.th32ProcessID == pid)
                    return 0;
            } while (Process32Next(pss, &pe));
        }

        CloseHandle(pss);

        return -1;
    }

#elif defined(BOOST_POSIX_API)

    // 0 : running, -1 : exit, -2 : zombie
    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; // zombie
                }
            }
        }
        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    // if not a child process,will not kill the process correctly
        {
    
    
            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();
            // detach as a single process
            c.detach();
        }
        catch (boost::process::process_error &exc)
        {
    
    
            err = exc.what();
            pid = -1;
        }
        return std::make_tuple(pid, err);
    }
} // namespace ProcessHelper

测试代码

#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;
    }

    // 根据进程名查询所有的pids
    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;
}

猜你喜欢

转载自blog.csdn.net/stallion5632/article/details/126200625