在C ++中终止一个线程以及它产生的任何进程

时间:2015-08-02 14:36:36

标签: c++ multithreading process kill pid

我在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

提前致谢。

1 个答案:

答案 0 :(得分:0)

std::thread类没有提供任意终止活动执行线程的方法。当前的C ++标准中没有实现此功能。

您发布的示例代码几乎是唯一可以使用C ++和C库中的功能完成的。

POSIX线程API是另一种选择。它确实提供了终止活动线程的方法;然而,当使用pthread_cancel()终止执行线程时,它会带来许多重要的警告,并且很难避免未定义的行为,因为这将无法正确展开已终止线程的堆栈并调用所有必要的破坏者;此外,执行线程必须到达取消点,以使pthread_cancel()生效。

此外,如果执行线程执行另一个进程,则新进程将替换线程的整个进程,而不仅仅是执行线程的上下文。如果这一直是你的意图,那么试图取消这个主题并不会带来太大的好处,你几乎必须做你已经在做的事情。