我正在 Linux 上用 C++ 编写一个模糊器。它产生多个线程,并在线程因任何原因挂起时具有超时功能。在计时器用完后,我无法找出终止线程的正确方法。我现在正在做的是:
`
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <chrono>
#include <thread>
#include <stdlib.h>
#include <sys/wait.h>
#include <stdio.h>
#include <vector>
#include <iostream>
#include <sys/time.h>
#include <random>
#include <cstdlib>
#include <climits>
#include <sstream>
#include <iomanip>
#include <unistd.h>
#include <cstring>
#define READ 0
#define WRITE 1
void reaper (int c_pid, int t_timeout) {
std::this_thread::sleep_for(std::chrono::milliseconds(t_timeout));
kill (c_pid, 9);
}
FILE * popen2 (std::string command, std::string type, int & pid, std::string low_lvl_user) {
pid_t child_pid;
int fd[2];
pipe(fd);
if((child_pid = fork()) == -1) {
perror("fork");
exit(1);
}
if (child_pid == 0) { // child begins
if (type == "r") {
close(fd[READ]); //Close the READ
dup2(fd[WRITE], 1); //Redirect stdout to pipe
}
else {
close(fd[WRITE]); //Close the WRITE
dup2(fd[READ], 0); //Redirect stdin to pipe
}
if (getuid() == 0) {
execl("/bin/su", "su", "-c", "/bin/sh", "-c", command.c_str(), low_lvl_user.c_str(), NULL); // fixes not being able to reap suid 0 processes
}
else {
execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL); // runs it all
}
exit(0);
}
else {
if (type == "r") {
close(fd[WRITE]); //Close the WRITE
}
else {
close(fd[READ]); //Close the READ
}
}
pid = child_pid;
if (type == "r") {
return fdopen(fd[READ], "r");
}
return fdopen(fd[WRITE], "w");
}
int pclose2(FILE * fp, pid_t pid) // close it so we don't fuck outselves
{
int stat;
fclose(fp);
while (waitpid(pid, &stat, 0) == -1) {
if (errno != EINTR) {
stat = -1;
break;
}
}
return stat;
}
int spawn_ch (std::string out_str) {
std::string low_lvl_user = "nobody";
int t_timeout = 500;
int pid; // initializes child
FILE * fp = popen2(out_str, "r", pid, low_lvl_user); // opens child process fork
char command_out[4096] = {0};
std::stringstream output;
std::thread reaper_thread(reaper, pid, t_timeout); // takes care of killing it off if it takes too long
reaper_thread.join();
while (read(fileno(fp), command_out, sizeof(command_out)-1) != 0) {
output << std::string(command_out);
memset(&command_out, 0, sizeof(command_out));
}
pclose2(fp, pid);
std::string token;
}
int main () {
std::string command = "HOME=AAAAAAAAA MAIL=AA /usr/sbin/exim4 -Ac AAAAAA -G -MCP,9,-Mar -Mf -Mset b -S 999999 -X,,-bF 999 -bdf -bpc -bpr -bpru,,-bt -exim4,AAA, -f,AAAAAAAAA,-oA -oMa,5Mu^i, -oMaa,, -oMas,,-oMs -oX isotanr -odb -oee -oem,999, -oo,99999999 -r 999999999 -t -ti 999999";
std::vector<std::thread> threads;
int num_threads = 2;
for (int cur_thread=1; cur_thread <= num_threads; ++cur_thread) threads.push_back(std::thread(spawn_ch, command)); // Thrift Shop
for (auto& all_thread : threads) all_thread.join(); // is that your grandma's coat?
exit(0);
}
但是由于在这个例子中进程被生成为 suid 101(或 0,或其他任何东西),kill 函数可以作为 root 运行以获取它生成的进程......这会起作用,除了 exim4 显然试图产生多个进程,当一个进程死亡时,其他进程不会。有没有办法让程序知道产生了哪些进程来杀死它们,或者最好是终止产生它们的整个线程的方法(我认为这应该有效,就好像你 ctrl+c 我的程序它会杀死它产生了什么)?
整个代码库在 github 上.
提前致谢。
最佳答案
std::thread
类不提供任意终止事件执行线程的方法。此功能未在当前 C++ 标准中实现。
您发布的示例代码几乎是唯一可以完全使用 C++ 和 C 库中的功能完成的事情。
POSIX 线程 API 是另一种选择。它确实提供了终止事件线程的方法;然而,它伴随着许多重要的警告,并且很难避免未定义的行为,当使用 pthread_cancel()
终止执行线程时,因为这不会正确地展开终止线程的堆栈,并调用所有需要的析构函数;此外,执行线程必须到达取消点,以便 pthread_cancel()
生效。
此外,如果执行线程执行另一个进程,新进程将替换线程的整个进程,而不仅仅是执行线程的上下文。如果这一直是您的意图,那么尝试取消线程无论如何都不会有太大好处,您几乎必须做您已经在做的事情。
关于c++ - 终止 C++ 中的线程及其产生的任何进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31772948/