【问题标题】:Race condition on pthread_kill()?pthread_kill() 上的竞争条件?
【发布时间】:2021-03-04 12:42:27
【问题描述】:

pthread_kill() 的 Linux 手册有以下段落:

POSIX.1-2008 建议,如果实现检测到使用 生命周期结束后的线程 ID,pthread_kill() 应该返回错误 ESRCH。 glibc 实现返回 在可以检测到无效线程 ID 的情况下出现此错误。 但还要注意,POSIX 表示尝试使用线程 ID 生命周期已结束会产生未定义的行为,并尝试 例如,在调用 pthread_kill() 时使用无效的线程 ID 可以: 导致分段错误。

问题是,在检查线程 ID 是否有效和发出 pthread_kill() 之间,线程可能已经终止。使用pthread_kill() 本质上是不安全的,因为总是存在可能变成未定义行为的竞争条件?

如何确保线程 ID 有效?

【问题讨论】:

  • 确切地说,线程必须被终止并且加入或分离,因为它现在无效的线程 ID 来呈现这场比赛。在严格的 POSIXy 语言中,terminated thread is still within its lifetime 只是“非活动”(不再运行但尚未分离/加入)。也就是说,好问题。
  • between checking the thread ID is valid and issuing the pthread_kill(), the thread might have terminated 你是说,里面 pthread_kill 打电话?这很简单 - pthread_kill 具有内部全局锁,所以它不会发生,不是吗?
  • @KamilCuk 不在pthread_kill 内部,而是在我决定调用pthread_killif 和调用本身之间。
  • 你为什么要检查它?只需拨打pthread_kill
  • 通常在我有理由相信是有效的线程 ID 上触发 pthread_kill。但是在触发和调用之间,一个分离的线程可能已经结束。

标签: linux pthreads posix


【解决方案1】:

pthread_kill() 上的竞争条件?

当线程分离时,总是如此。但如果线程 ID 有效,则不会。

使用 pthread_kill() 本质上是不安全的,因为总是存在可能变成未定义行为的竞争条件?

不,并非总是如此。

如何确保线程 ID 有效?

来自POSIX thread ID

如果线程 ID 的生命周期在线程终止后结束,则如果它是使用设置为 PTHREAD_CREATE_DETACHED 的 detachstate 属性创建的,或者已为该线程调用了 pthread_detach() 或 pthread_join()。

否则有效。所以当线程没有分离也没有加入时,线程ID是有效的,你随时可以用它调用pthread_kill()

通常,您应该停止使用pthread_detachpthread_join 之后的线程ID。就像malloc() 中的free() - 你不能在free() 之后使用malloc() 分配的内存。与分离或加入后不能使用线程 ID 的方式相同,线程 ID 只是变得无效。只是使用pthread_detach,它在“以后”变得无效,但你不知道什么时候,所以无论如何你都不能使用它(好吧,除非你自己编写同步)。它可能在调用pthread_detach 后立即失效。如果您打算使用线程 ID 进行任何操作,请不要分离并且不要加入它。

使用“非活动线程”(已终止的非分离非连接线程)对pthread_kill 的调用是有效 - 线程 ID 仍然有效。我们可以从pthread_kill posix阅读:

现有实现因 pthread_kill() 的结果而异,其线程 ID 指示非活动线程(尚未分离或连接的终止线程)。一些表示此类调用成功,而另一些则给出 [ESRCH] 错误。由于本卷 POSIX.1-2017 中线程生命周期的定义涵盖了非活动线程,因此所描述的 [ESRCH] 错误在这种情况下是不合适的。特别是,这意味着应用程序不能使用 pthread_kill() 让一个线程检查另一个线程是否终止。

未来的方向

该标准的未来版本可能要求 pthread_kill() 在向非活动线程(尚未分离或加入的终止线程)发送信号的情况下不会因 [ESRCH] 而失败,即使不会传递任何信号,因为因为线程不再运行。

FUTURE DIRECTIONS 看起来更喜欢带有非活动线程的 pthread_kill() 应该成功并返回 0。我个人喜欢这种情况下的 ESRCH 错误。

【讨论】:

    【解决方案2】:

    如何确保线程 ID 有效?

    您必须重新设计,以便您的代码知道这一点先验。*任何缺少的都是TOCTOU race (CWE-367)

    幸运的是,interprocess killing 提供了很多现有技术。进程间信号不会像pthread_kill 那样冒着未定义行为的可怕风险,但细心的编码人员认为发出回收 PID 信号的风险是不可接受的。 (以及线程 ID can be recycled, too。)

    * 好的,您可以通过检查一些人为的状态来做到这一点。例如,在线程例程的最后,将 mutex-protected i_am_still_running 标志设置为 false。然后只有pthread_kill 该线程同时持有互斥锁并确认它仍在运行。呸。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 2018-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多