在终止的线程上调用pthread_cancel()安全吗?

在终止的线程上调用pthread_cancel()安全吗?,c,pthreads,posix,C,Pthreads,Posix,我想知道在终止的线程上调用pthread\u cancel()是否安全。我在手册页上找不到任何提示。提前感谢您的任何提示 编辑:也许我不够准确。我说的不是由前面的pthread_cancel()终止的线程,而是从线程函数返回的线程 我认为需要安全,否则pthread\u cancel会有问题(除了不可用之外) 事实上,如果它不安全,那么对pthread\u cancel的每次调用都必须通过检查线程是否处于活动状态(并确保它在取消之前保持活动状态)而变得非常复杂。简单的“你还在吗”是不行的 总之,

我想知道在终止的线程上调用
pthread\u cancel()
是否安全。我在手册页上找不到任何提示。提前感谢您的任何提示


编辑:也许我不够准确。我说的不是由前面的pthread_cancel()终止的线程,而是从线程函数返回的线程

我认为需要安全,否则
pthread\u cancel
会有问题(除了不可用之外)

事实上,如果它不安全,那么对
pthread\u cancel
的每次调用都必须通过检查线程是否处于活动状态(并确保它在取消之前保持活动状态)而变得非常复杂。简单的“你还在吗”是不行的

总之,如果线程终止,我相信
pthread\u cancel
必须是安全的。当然,终止和连接的线程可能不是这种情况。

错误顶部

  ESRCH  No thread with the ID thread could be found.

ESRCH

线程未指定进程中当前正在运行的线程

如果实现在其生命周期结束后检测到线程ID的使用,建议函数失败并报告[ESRCH]错误

更新

在NPTL中有一个

所以,退出后的第二次取消或取消将是死线程的一个noop

退出的\u位掩码由

__do_cancel是对和的反应


不,在已终止的线程上调用pthread_cancel()是不安全的


原因是实现可能会将终止线程的线程ID重新用于另一个线程,并且在该TID上调用“pthread_cancel()”可能会触发不应终止或未定义行为的线程的终止。

是的,在调用pthread_detach或pthread_join之前调用它是安全的。 但是,根据我的实验,如果线程已经从其线程函数返回,它可以返回ESRCH(=3)。(gcc(Ubuntu 7.5.0-3ubuntu1~18.04)7.5.0)


是的,但即使线程终止,也可能会调用
pthread\u join
,因此当线程结束时,它的ID仍然有效。我认为问题在于所提到的生存期是如何定义的。它是指定线程终止的时间还是指调用pthread_join()的时间?domachine,从的链接是这样的:如果创建线程时将detachstate属性设置为pthread_CREATE_DETACHED,或者pthread_detach()或pthread_join()时,线程ID的生存期在线程终止后结束是的,我知道。我只是说说而已。这是一个很好的问题,回答的信息非常丰富。尽管文档中可能会提到生命周期和有效的线程ID,但在我的普通Debian Wheezy系统上,对终止的线程调用
pthread\u cancel
会导致返回值为-1,并将
errno
设置为
ESRCH
。这对我来说很有意义。谢谢你的回答!简单规则:pthread_t在线程终止(如果分离)或连接(如果未连接)之前有效。这意味着您可以安全地pthread_取消分离的线程,前提是您知道它尚未终止。您可以安全地pthread_取消未分离的线程,只要您知道它尚未被pthread_连接。这个答案是错误的。线程id的生存期将一直延长,直到它被加入或分离并退出。
  /* We are canceled now.  When canceled by another thread this flag
     is already set but if the signal is directly send (internally or
     from another process) is has to be done here.  */
  int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;

  if (oldval == newval || (oldval & EXITING_BITMASK) != 0)
    /* Already canceled or exiting.  */
    break;
/* Called when a thread reacts on a cancellation request.  */
static inline void
__attribute ((noreturn, always_inline))
__do_cancel (void)
{
  struct pthread *self = THREAD_SELF;

  /* Make sure we get no more cancellations.  */
  THREAD_ATOMIC_BIT_SET (self, cancelhandling, EXITING_BIT);
void
__pthread_exit (value)
     void *value;
{
  THREAD_SETMEM (THREAD_SELF, result, value);

  __do_cancel ();
#include "gtest/gtest.h"

static void *S_ThreadEntry1(void* pvarg)
{
     return 0;
}

TEST(ThreadTest, PthreadCancelAfterExit)
{
     pthread_t threadid;
     ASSERT_EQ(pthread_create(&threadid, 0, &S_ThreadEntry1, nullptr), 0);
     sleep(1);

     int cancel_ret = pthread_cancel(threadid);
     std::cout << "pthread_cancel returned " << cancel_ret << std::endl;
     if (cancel_ret != 0)
          EXPECT_EQ(cancel_ret, ESRCH);
     void* res;
     EXPECT_EQ(pthread_join(threadid, &res), 0);
     std::cout << "res=" << res << std::endl;
}
[ RUN      ] ThreadTest.PthreadCancelAfterExit
pthread_cancel returned 3
res=0
[       OK ] ThreadTest.PthreadCancelAfterExit (1000 ms)