将一个线程(卡住的)从另一个线程终止



只使用标准C++(没有特定于平台的API),我想启动一个可以立即完成或超时的外部应用程序。如果应用程序停止,我的应用程序会有一个超时,之后它会简单地终止应用程序并重新启动它

现在,归根结底,我尝试启动两个线程:

  • 第一个线程启动应用程序并等待它终止
  • 第二个线程等待几秒钟并检查第一个线程是否终止。如果它没有这样做,那么它就认为它停滞不前

问题是,如何从第二个线程终止第一个线程?我启动应用程序的方式是使用system()函数。它是同步的,所以如果我希望终止,我没有任何方法从那个线程进行检查。它必须以某种方式通过一个例外,从外部强制执行。

这是如何正确完成的?7

附言:如果这不可能,我怀疑也不可能,那么我就是不想再等那个线程了。它可以简单地保持在后台。我该如何做到这一点?(目前,我正在等待带有join()的线程)

不能强制终止另一个线程。你只能礼貌地要求它退出。这适用于C++和POSIX线程模型。Windows有TerminateThread,但它非常危险,几乎无法使用。POSIX具有pthread_cancel。这是合作终止,这可能符合您的要求,但没有标准的C++等价物。

即使您以某种方式终止了一个线程,它也不会对它可能通过system启动的任何程序产生任何影响。

若要让线程释放而不必对join承担任何义务,请使用thread::detach()

为了回答您关于杀死线程的问题,POSIX提供了两个功能:

pthread_cancel();

这将使线程停止在取消点

另一种是:

pthread_kill();

此函数将向线程发送一个信号。与取消指针的概念相反,这种情况可以发生在线程中的任何点。换句话说,如果线程有一个互斥锁在那个时候被锁定,你就会失去这个锁。。。(除非您干净地处理该线程中的信号)。

然而,您所描述的是一个system()调用,它是在一个单独的线程中进行的,这样您就不会被阻塞。我认为这两个函数都不会对您有所帮助,因为还有另一个进程在运行,而不仅仅是一个简单的线程。你需要的是停止另一个过程。

在您的情况下,您需要做的是找出孩子(或多个孩子)的pid,并向该孩子进程(或所有孩子和孙子女,等等)发送信号。在这种情况下,您使用kill()函数,如下所示:

kill(child_pid, SIGINT);

一旦孩子死亡并被清理干净,system()调用将返回,并且您的线程已准备好加入。所以按顺序,你可以:

...
child_pid = find_child_pid();   // Note: there is no such function, you have to write it or use a library which offers such
kill(child_pid, SIGNINT);
pthread_join(thread_id);

如果该子进程可以创建子进程,并且您也希望它们不在画面中(就像在shell中,当您点击Ctrl-C时),那么您需要找到您的子进程的所有子进程及其子进程等。您可以通过查看每个进程的PPID(父PID)来查看它是否与其中一个子进程匹配。该信息在/proc/<pid>/stat/proc/<pid>/status中可用。(第一个文件可能是最好的,因为它只有一行,但是,要越过进程名称很难,因为它可能包括括号……所以你必须确保从行尾搜索")"(否则你可能会从程序名称中找到))。一旦你得到了,跳过该州,就会有PPID。(所以) S <ppid>)。

重复搜索,直到找到所有父级/子级,然后开始向它们中的每一个发送SIGINT、SIGTERM或SIGKILL。

正如另一个答案中所提到的,您可以使用pthread_detach()退出您的软件,并将其他线程抛在后面。如果您希望其他进程在主进程结束之前结束,那么这可能就不太可取了。这在很大程度上也取决于你想要完成什么。

另一种可能更复杂的方法是使用fork()+execve()。这意味着你必须重新实现你自己的system()调用,但优点是你不需要线程,并且你可以免费获得子的pid(也就是说,你可以在不搜索子pid的情况下杀死它)。如果需要运行的函数不是用一组不同的命令行参数动态定义的,那么它就不会太复杂。如果您需要更改stdin、stdout、stderr,并且参数取决于各种因素,那么它将变得更加复杂。。。

最新更新