pthread_cancel() 是否有可能终止另一个意外的线程?
Is it possible that pthread_cancel() terminates another unintended thread?
我的问题与this one类似。但是看完它的所有答案,我仍然不知道pthread_cancel()能得到什么样的安全保障。所以我想问一个更具体的问题:
假设 pthread_cancel() 在名为 my_thread 的 pthread_t 变量上调用,是否有可能到 pthread_cancel(my_thread ) 被执行时,对应于 my_thread 的实际线程已经以某种方式终止,内核为另一个新创建的线程回收了 my_thread 的值,这样通过执行 pthread_cancel(my_thread), 另一个意外的线程被杀死了?
在分离或加入线程之前,该值不能是 "recycled"。只要你没有做任何这些事情,调用 pthread_cancel 是安全的,即使线程已经终止。
问题是关于 pthread_cancel()
的竞争条件。 POSIX 要求该函数在使用该术语的特定的、有限的意义上是线程安全的,但这并不能真正说明手头的问题。关键细节在 XSH 2.9.2 中指定,正如 @R.. 在前面的评论中观察到的那样。特别是:
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. A conforming implementation is free to reuse a thread ID after
its lifetime has ended. If an application attempts to use a thread ID
whose lifetime has ended, the behavior is undefined.
因此,允许应用程序重新使用生命周期已结束的线程 ID,但这实际上是一个附带问题,因为如果您尝试使用陈旧的线程 ID,则行为是未定义的,无论 ID 是否已被重新使用.当然,在所描述的案例中可能发生的无数 UB 表现形式之一确实是取消了与您打算取消的线程不同的线程,无论线程 ID 是否已被重用。
线程 ID 的生命周期在它标识的线程终止时结束(如果该线程是分离创建的),或者当它被传递给 pthread_detach
或 pthread_join
(如果线程是可连接创建的)。完全有可能在 pthread_cancel
的执行之间进行竞争。如果创建的线程是可连接的,那么您总共至少需要三个线程,但如果创建的线程是分离的,那么除了调用 pthread_cancel
的线程和一个被取消的单独线程之外,您不需要任何其他线程。无论哪种方式 pthread_cancel
都是有风险的。
您链接的问题的公认答案充其量是误导性的,但@DavidSchwartz 对此的评论更有用,即使我认为它没有准确反映每个细节的规范。我会这样说:
如果以下情况之一成立,则使用 pthread_cancel
取消线程是安全的:
- 创建的线程是可连接的,并且可以肯定的是它在
pthread_cancel
调用完成之前不能被分离或连接,或者
- 线程是分离创建的,可以肯定它不会终止,也不会在
pthread_cancel
调用完成。
尝试取消不安全(即它有 UB 的风险)
创建的线程可通过 pthread_create
提供的线程 ID 创建,如果在 pthread_cancel
调用完成之前可以分离或加入该线程, 或
创建的线程分离,如果该线程有可能终止或在 pthread_cancel
调用之前调用 pthread_join
或 pthread_detach
完成。
目前尚不清楚通过分离后从 pthread_self()
获得的线程 ID 取消创建为可连接但后来分离的线程是否安全,如果确定两者都不是pthread_join
或 pthread_detach
都不能在 `pthread_cancel 完成之前对该线程 ID 调用。*
*可以将规范解释为暗示在那些情况下,pthread_self
returns 一个线程 ID 的生命周期已经结束,因此取消肯定会产生 UB。但是至少有几个不同的相反解释,并且在任何一种情况下,都没有定义来自 pthread_self
的线程 ID 的生命周期在程序结束之前结束的条件,从而可以安全地取消随时通过该 ID 进行讨论。
我的问题与this one类似。但是看完它的所有答案,我仍然不知道pthread_cancel()能得到什么样的安全保障。所以我想问一个更具体的问题:
假设 pthread_cancel() 在名为 my_thread 的 pthread_t 变量上调用,是否有可能到 pthread_cancel(my_thread ) 被执行时,对应于 my_thread 的实际线程已经以某种方式终止,内核为另一个新创建的线程回收了 my_thread 的值,这样通过执行 pthread_cancel(my_thread), 另一个意外的线程被杀死了?
在分离或加入线程之前,该值不能是 "recycled"。只要你没有做任何这些事情,调用 pthread_cancel 是安全的,即使线程已经终止。
问题是关于 pthread_cancel()
的竞争条件。 POSIX 要求该函数在使用该术语的特定的、有限的意义上是线程安全的,但这并不能真正说明手头的问题。关键细节在 XSH 2.9.2 中指定,正如 @R.. 在前面的评论中观察到的那样。特别是:
The lifetime of a thread ID ends after the thread terminates if it was created with the
detachstate
attribute set toPTHREAD_CREATE_DETACHED
or ifpthread_detach()
orpthread_join()
has been called for that thread. A conforming implementation is free to reuse a thread ID after its lifetime has ended. If an application attempts to use a thread ID whose lifetime has ended, the behavior is undefined.
因此,允许应用程序重新使用生命周期已结束的线程 ID,但这实际上是一个附带问题,因为如果您尝试使用陈旧的线程 ID,则行为是未定义的,无论 ID 是否已被重新使用.当然,在所描述的案例中可能发生的无数 UB 表现形式之一确实是取消了与您打算取消的线程不同的线程,无论线程 ID 是否已被重用。
线程 ID 的生命周期在它标识的线程终止时结束(如果该线程是分离创建的),或者当它被传递给 pthread_detach
或 pthread_join
(如果线程是可连接创建的)。完全有可能在 pthread_cancel
的执行之间进行竞争。如果创建的线程是可连接的,那么您总共至少需要三个线程,但如果创建的线程是分离的,那么除了调用 pthread_cancel
的线程和一个被取消的单独线程之外,您不需要任何其他线程。无论哪种方式 pthread_cancel
都是有风险的。
您链接的问题的公认答案充其量是误导性的,但@DavidSchwartz 对此的评论更有用,即使我认为它没有准确反映每个细节的规范。我会这样说:
如果以下情况之一成立,则使用
pthread_cancel
取消线程是安全的:- 创建的线程是可连接的,并且可以肯定的是它在
pthread_cancel
调用完成之前不能被分离或连接,或者 - 线程是分离创建的,可以肯定它不会终止,也不会在
pthread_cancel
调用完成。
- 创建的线程是可连接的,并且可以肯定的是它在
尝试取消不安全(即它有 UB 的风险)
创建的线程可通过
pthread_create
提供的线程 ID 创建,如果在pthread_cancel
调用完成之前可以分离或加入该线程, 或创建的线程分离,如果该线程有可能终止或在
pthread_cancel
调用之前调用pthread_join
或pthread_detach
完成。
目前尚不清楚通过分离后从
pthread_self()
获得的线程 ID 取消创建为可连接但后来分离的线程是否安全,如果确定两者都不是pthread_join
或pthread_detach
都不能在 `pthread_cancel 完成之前对该线程 ID 调用。*
*可以将规范解释为暗示在那些情况下,pthread_self
returns 一个线程 ID 的生命周期已经结束,因此取消肯定会产生 UB。但是至少有几个不同的相反解释,并且在任何一种情况下,都没有定义来自 pthread_self
的线程 ID 的生命周期在程序结束之前结束的条件,从而可以安全地取消随时通过该 ID 进行讨论。