pthread_kill() 上的竞争条件?

Race condition on pthread_kill()?

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

POSIX.1-2008 recommends that if an implementation detects the use of a thread ID after the end of its lifetime, pthread_kill() should return the error ESRCH. The glibc implementation returns this error in the cases where an invalid thread ID can be detected. But note also that POSIX says that an attempt to use a thread ID whose lifetime has ended produces undefined behavior, and an attempt to use an invalid thread ID in a call to pthread_kill() can, for example, cause a segmentation fault.

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

如何保证线程ID有效?

Race condition on pthread_kill()?

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

Is it inherently unsafe to use pthread_kill(), as there is always a race condition that can turn into a undefined behavior?

不,不总是。

How to ensure thread ID will be valid?

来自 POSIX thread ID:

The lifetime of a thread ID ends after the thread terminates if it was created with the detachstate attribute set to PTHREAD_CREATE_DETACHED or if pthread_detach() or pthread_join() has been called for that thread.

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

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

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

读取

Existing implementations vary on the result of a pthread_kill() with a thread ID indicating an inactive thread (a terminated thread that has not been detached or joined). Some indicate success on such a call, while others give an error of [ESRCH]. Since the definition of thread lifetime in this volume of POSIX.1-2017 covers inactive threads, the [ESRCH] error as described is inappropriate in this case. In particular, this means that an application cannot have one thread check for termination of another with pthread_kill().

FUTURE DIRECTIONS

A future version of this standard may require that pthread_kill() not fail with [ESRCH] in the case of sending signals to an inactive thread (a terminated thread not yet detached or joined), even though no signal will be delivered because the thread is no longer running.

FUTURE DIRECTIONS 看起来更喜欢 pthread_kill() 和不活动的线程应该成功并且 return 0。我个人喜欢这种情况下的 ESRCH 错误。

How to ensure thread ID will be valid?

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

幸运的是,有很多来自 interprocess killing 的现有技术。进程间信号不会 运行 像 pthread_kill 那样的未定义行为的可怕风险,但细心的编码人员认为发出循环 PID 信号的风险是不可接受的。 (和线程 ID can be recycled, too。)

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