【问题标题】:Check if pthread is still alive in Linux C检查 pthread 在 Linux C 中是否仍然存在
【发布时间】:2018-04-12 11:41:34
【问题描述】:

我知道有人问过类似的问题,但我认为我的情况有点不同。我需要检查子线程是否还活着,如果它不是打印错误消息。子线程应该一直运行。所以基本上我只需要非阻塞 pthread_join 并且在我的情况下没有竞争条件。子线程可以被杀死,所以我不能在子线程完成时设置某种共享变量,因为在这种情况下不会设置它。

可以这样杀死子线程:

kill -9 child_pid

编辑:好吧,这个例子是错误的,但我仍然确定存在以某种方式杀死特定线程的方法。

编辑:我这样做的动机是在我的应用程序中实现需要此检查的另一层安全性。尽管可以绕过此检查,但那是另一回事了。

编辑:假设我的应用程序旨在作为逆向工程学生的演示。他们的任务是破解我的应用程序。但是我在子线程中设置了一些反黑客/反调试障碍。我想确保这个子线程保持活跃。正如一些 cmets 所提到的 - 在不弄乱父母的情况下杀死孩子可能并不容易,所以也许这个检查是没有必要的。主线程中也存在安全检查,但这次我需要将它们添加到另一个线程中以使主线程响应。

【问题讨论】:

  • 我会考虑不同的设计。您可以拥有以例如结尾的线程更改(在某些互斥体下)全局标志。
  • 但我不需要结束任何线程。我只是想确保我的从属线程仍然活着,并在它死后进行一些错误处理(不使用从属线程)。
  • 解释线程将如何被杀死。在您的问题中显示一些minimal reproducible example。您需要大量改进您的问题,所以请编辑您的问题
  • 子线程,还是子进程?
  • 不能用kill -9 杀死线程。您一定在考虑流程。

标签: c linux pthreads


【解决方案1】:

被什么杀死,为什么那个东西不能表明线程已经死了?但即便如此,这听起来也很可疑

如果您需要检查线程/进程是否处于活动状态,这几乎是普遍的设计错误 - 代码中的逻辑应隐式处理此问题。

在您的编辑中,您似乎想对线程被完全外部的东西杀死的可能性做点什么。

嗯,好消息。如果不降低整个过程,就没有办法做到这一点。线程的所有非自愿死亡方式都会杀死进程中的所有个线程,除了取消之外,这只能由同一进程中的其他东西触发。

【讨论】:

  • 这更像是一个长评论而不是一个答案。
  • 我相信这不是设计问题,因为我正在实施额外的安全检查。
  • @jozols 我相信这不是设计问题,因为我正在实施额外的安全检查。您认为这样的检查可以增加什么安全性?任何有权终止子线程或进程的人都可以操纵您的环境以返回错误的结果。
  • 是的,但我没有构建防弹解决方案,因为我知道它无法完成。只需添加另一层。
  • 本月@employee - 如果可能,请在您的最后一句话中添加来源。
【解决方案2】:

kill(1) 命令不会向某个线程发送信号,而是向整个process 发送信号。仔细阅读signal(7)pthreads(7)

信号和线程不能很好地混合在一起。根据经验,您不想同时使用两者。

顺便说一句,使用kill -KILLkill -9 是错误的。接收进程没有机会处理SIGKILL 信号。你应该使用SIGTERM ...

如果您想在多线程应用程序中处理SIGTERM,请阅读signal-safety(7) 并考虑将一些pipe(7) 设置为self(并在某些事件循环中使用poll(2)),信号处理程序将write(2) .这个众所周知的技巧在Qt documentation 中有很好的解释。您还可以考虑signalfd(2) Linux 特定的系统调用。

如果您考虑使用pthread_kill(3),则可能不适合您的情况(但是,将其与 0 信号一起使用是检查线程是否存在的一种有效但粗略的方法)。阅读一些Pthread tutorial。不要忘记pthread_join(3)pthread_detach(3)

子线程应该一直运行。

这是错误的方法。您应该知道子线程何时以及如何终止,因为您正在对传递给pthread_create(3) 的函数进行编码,并且您应该在那里处理所有错误情况并添加相关的清理代码(可能还有同步)。所以子线程应该运行多久就运行多久,并且应该在结束时执行适当的清理操作。

还要考虑其他一些inter-process communication 机制(如socket(7)fifo(7) ...);它们通常比信号更适合,特别是对于多线程应用程序。例如,您可以将您的应用程序设计为一些专门的 Web 或 HTTP 服务器(使用 libonion 或其他一些 HTTP 服务器库)。然后,您将使用 Web 浏览器或一些 HTTP 客户端命令(如 curl)或 HTTP 客户端库(如 libcurl)来驱动您的多线程应用程序。或者在您的应用程序中添加一些 RPC 功能,可能使用 JSONRPC

(你对信号的假定用法闻起来很糟糕,很可能是XY problem;强烈考虑使用更好的东西)

我这样做的动机是在我的应用程序中实现另一层安全性

我完全不明白。信号和线程如何增加安全性?我猜你正在降低软件的安全性。

我想确保这个子线程保持活动状态。

除了通过良好的编码和避免错误之外,您无法确定(但请注意Rice's theoremHalting Problem:不可能有任何可靠和健全的static source code program analysis 来检查)。如果其他东西(例如其他线程,甚至是您自己的错误代码)是例如任意修改你的线程的call stack,你就有undefined behavior,你可以很scared

实践中,gdb 调试器、address and thread sanitizers、其他编译器instrumentation optionsvalgrind 等工具可以帮助找到大多数此类错误,但有No Silver Bullet

也许你想利用process isolation,但是你应该放弃你的多threading方法,并考虑一些multi-processing方法。根据定义,线程与同一process 的其他线程共享大量资源(尤其是它们的virtual address space)。因此,您的问题中提到的安全检查没有多大意义。我猜他们正在添加更多代码,但只会降低安全性(因为你会有更多错误)。

阅读像Operating Systems: Three Easy Pieces 这样的教科书应该是值得的。

【讨论】:

  • 是的,你是对的。但关键是线程可以以某种方式被杀死,甚至是残酷的。
  • 如果一个线程被残忍地杀死,你的程序在这种情况下很可能会出现一些undefined behavior
  • 谢谢,我会尝试寻找证据证明线程不能被杀死而不避免父线程异常行为(即使父线程没有与子线程交互)。
  • “信号和线程如何增加安全性?”这很简单。 Thread 不时在后台执行一些安全检查。我需要确保该线程仍在运行,如果没有,则说明存在漏洞。
  • @jozols:请不要在这里发表评论。花点时间编辑您的问题,它需要显着改进才能有意义。目前,它令人困惑。您的问题附近有一个edit 超链接,请多使用它。而“时不时的安检”是一种深刻而危险的幻想。您需要更多地介绍您的应用程序和项目!
【解决方案3】:

您可以使用pthread_kill() 来检查线程是否存在。

概要

#include <signal.h>

int pthread_kill(pthread_t thread, int sig);

描述

pthread_kill() 函数应请求传递信号 到指定的线程。

和kill()一样,如果sig为零,则进行错误检查 但实际上不会发送任何信号。

类似

int rc = pthread_kill( thread_id, 0 );
if ( rc != 0 )
{
    // thread no longer exists...
}

不过,正如其他地方的其他人所说,它并不是很有用,而且它作为任何类型的安全措施都非常薄弱。任何有权杀死线程的东西都可以在不杀死它的情况下阻止它运行,或者让它运行任意代码,这样它就不会做你想做的事情。

【讨论】:

  • 我读过 pthread_kill 如果线程已经死了,它会导致未定义的行为。
  • @jozols 什么未定义的行为? “僵尸”线程(不再运行但未加入)存在问题,可以通过使用分离线程来解决,但如果您正在跟踪线程 ID 并为您的进程设置一个唯一的,我看不到任何内容与未定义行为相关的 POSIX 标准。
  • @jozols POSIX states 如果实现在其生命周期结束后检测到线程 ID 的使用,建议该函数失败并报告 [ESRCH] 错误。 我没有查看整个 POSIX 标准,但在 pthread_kill() 文档中根本没有提到未定义的行为,并且它专门针对不再存在的线程调用了推荐的结果。
猜你喜欢
  • 2019-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-30
  • 2015-04-02
  • 2020-01-27
  • 1970-01-01
相关资源
最近更新 更多