我在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。
提前致谢。
答案 0 :(得分:0)
std::thread
类没有提供任意终止活动执行线程的方法。当前的C ++标准中没有实现此功能。
您发布的示例代码几乎是唯一可以使用C ++和C库中的功能完成的。
POSIX线程API是另一种选择。它确实提供了终止活动线程的方法;然而,当使用pthread_cancel()
终止执行线程时,它会带来许多重要的警告,并且很难避免未定义的行为,因为这将无法正确展开已终止线程的堆栈并调用所有必要的破坏者;此外,执行线程必须到达取消点,以使pthread_cancel()
生效。
此外,如果执行线程执行另一个进程,则新进程将替换线程的整个进程,而不仅仅是执行线程的上下文。如果这一直是你的意图,那么试图取消这个主题并不会带来太大的好处,你几乎必须做你已经在做的事情。