文章目录
1. 概要
在Linux系统中,进程管理是核心组件,涵盖了创建、调度、暂停、恢复和终止等关键操作。
本文将详细介绍基于C++的进程管理工具的设计与实现,包括进程的查找、暂停、恢复和终止功能。
- 完整代码见process_helper
- 本文单元测试 gtest单元测试:进程冻结与恢复管理模块的单元测试
2. 进程管理接口详解
2.1 进程冻结与恢复的基本概念
在Linux环境中,进程的管理涉及到对进程执行状态的控制,其中包括了进程的冻结(暂停)和恢复(继续执行)。这些操作通过发送特定的信号来实现,主要使用到 SIGSTOP
和 SIGCONT
信号。
2.2 进程查找与PID获取
为了准确控制目标进程,首先需要能够根据进程名称或者其他标识符获取到进程的PID。在Linux系统中,可以通过读取 /proc
文件系统来获取所有运行中进程的详细信息,包括进程的命令行参数和状态。
/**
* @brief Function to find the PID of a process by its name
* @param [in] processName process name
* @param [out] pid process id
* @return true - find pid by process name; false - not find pid by process name
*/
bool FindPidByProcessName(const std::string& processName, pid_t &pid);
2.3 进程冻结与恢复的实现
2.3.1 进程冻结
进程冻结通过发送 SIGSTOP
信号来实现,暂停进程的执行。实现方法包括使用 kill(pid, SIGSTOP)
函数调用,并等待进程状态确认操作成功。
/**
* @brief freeze process by pid
*
* @param [in] pid - pid find by process name.
* @return true - Freeze successfully; false - Freeze failed
*/
bool FreezeProcessByPid(pid_t pid);
2.3.2 进程恢复
一旦进程被冻结,可以通过发送 SIGCONT
信号来恢复其执行。恢复过程中可能需要多次尝试,以确保进程成功从暂停状态恢复到执行状态。
/**
* @brief try to resume a stopped process by pid
*
* @param [in] attempts - if resume failed, try another attempts times.
* @param [in] pid - pid find by process name.
* @return true - Resume successfully; false - Resume failed
*/
bool TryToResumeProcessByPid(pid_t pid, int attempts = 3);
2.4 进程终止
在某些情况下,需要强制终止一个进程以释放系统资源或确保安全性。可以使用 SIGKILL
信号立即终止进程的执行,但需要注意可能会造成数据丢失。
/**
* @brief terminate a process
*
* @param [in] processName - process name.
* @param [in] attempts - if resume failed, try another attempts times.
* @return 0 - successfully; -1 - not found process; -2 terminate failed
* -3 - Handle waitpid error
*/
int TerminateProcess(const std::string& processName, int attempts = 3);
2.5 进程状态监控与控制
在实现进程管理功能时,还需要监控进程的状态并根据需要进行控制。通过读取 /proc/[pid]/status
文件可以获取进程的详细状态信息,如是否处于停止状态。
/**
* @brief Function to check if the process is not in stopped state
*
* @param [in] pid - pid find by process name
* @return true - stopped; false - not stopped
*/
bool IsProcessStopped(pid_t pid);
3. 设计方案
本节将详细介绍如何设计并实现一个C++进程管理工具,包括查找、暂停、恢复和终止进程的功能。
3.1 文件和目录管理
为了实现进程查找功能,使用 <dirent.h>
头文件中的相关函数,通过读取 /proc
目录下的进程信息来获取进程的PID和命令行信息。
bool FindPidByProcessName(const std::string& processName, pid_t& pid) {
DirCloser dir(opendir("/proc"));
if (!dir.get()) {
std::cerr << "Failed to open directory /proc" << std::endl;
return false;
}
struct dirent* entry;
while ((entry = readdir(dir.get())) != nullptr) {
// Check if the entry is a directory and its name is numeric
if (entry->d_type == DT_DIR) {
std::string pidStr = entry->d_name;
if (pidStr.find_first_not_of("0123456789") == std::string::npos) {
// Read the "cmdline" file to get the process name
std::string cmdlinePath = "/proc/" + pidStr + "/cmdline";
std::ifstream cmdlineFile(cmdlinePath);
FileCloser fileCloser(cmdlineFile); // FileCloser to manage cmdlineFile
if (cmdlineFile.is_open()) {
std::stringstream cmdlineStream;
cmdlineStream << cmdlineFile.rdbuf();
std::string cmdLine = cmdlineStream.str();
// Check if the process name matches
if (cmdLine.find(processName) != std::string::npos) {
pid = std::stoi(pidStr);
return true;
}
} else {
std::cerr << "Failed to open " << cmdlinePath << std::endl;
}
}
}
}
return false;
}
3.2 进程状态监控与控制
通过 kill
系统调用发送信号来控制进程的状态,同时利用 /proc/[pid]/status
文件来获取进程的详细状态信息。
bool IsProcessStopped(pid_t pid) {
std::ifstream statusStream(std::string("/proc/") + std::to_string(pid) + "/status");
std::string line;
std::regex stateRegex("^State:\\s+([^\\(]+)\\(");
while (getline(statusStream, line)) {
std::smatch match;
if (std::regex_search(line, match, stateRegex)) {
std::string state = match[1].str(); // Get the matched state string
// Remove leading and trailing spaces using regex_replace
state = std::regex_replace(state, std::regex("^\\s+|\\s+$"), "");
if (state == "T") {
std::cerr << "Process " << pid << " status is " << state << " is in stopped state.\n";
return true;
} else {
std::cout << "Process " << pid << " status is " << state << " is not in stopped state.\n";
return false;
}
}
}
return true; // Error or process not found
}
3.3 进程管理接口
封装了对进程的操作函数,提供了友好的外部接口。
bool FreezeProcessByPid(pid_t pid) {
if (kill(pid, SIGSTOP) == -1) {
std::cerr << "Failed to send SIGSTOP to process, pid" << pid << std::endl;
return false;
} else {
std::cout << "Success to send SIGSTOP to process " << pid << std::endl;
}
usleep(1000); // sleep 1ms, wait for process status
if (IsProcessStopped(pid)) {
std::cerr << "Process " << pid << " freeze success." << std::endl;
return true;
}
return false;
}
bool TryToResumeProcessByPid(pid_t pid, int attempts) {
for (int i = 0; i < attempts; ++i) {
if (kill(pid, SIGCONT) == 0) {
usleep(1000); // sleep 1ms, wait for process status
if (!IsProcessStopped(pid)) {
std::cout << "Process " << pid << " resumed successfully.\n";
return true;
}
usleep(1000 * 100); // sleep 100ms, wait for another try
}
}
std::cout << "Failed to resume process " << pid << " after " << attempts << " attempts.\n";
return false;
}
int TerminateProcess(const std::string& processName, int attempts) {
pid_t pid;
if (!FindPidByProcessName(processName, pid)) {
std::cerr << "Cannot find process, " << processName << std::endl;
return -1;
}
for (int i = 0; i < attempts; ++i) {
if (kill(pid, SIGKILL) == 0) {
std::cout << "Process with PID: " << pid << " has been terminated.\n";
int status;
if (waitpid(pid, &status, 0) == -1) {
std::cerr << "Error waiting for process " << pid << ": " << strerror(errno) << std::endl;
return -3; // Handle waitpid error
}
return 0;
} else {
std::cerr << "Failed to kill process with PID: " << pid << std::endl;
}
}
std::cerr << "Failed to kill process with PID: " << pid << " after " << attempts << " attempts.\n";
return -2; // Handle kill attempts failure
}