在终止线程上调用pthread_cancel()是否安全?

时间:2011-08-29 20:14:54

标签: c pthreads posix

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

编辑:也许我不够准确。我谈论由早期的pthread_cancel()终止的线程,但是关于简单地从它们的线程函数返回的线程。

4 个答案:

答案 0 :(得分:11)

我认为需要是安全的,或pthread_cancel会有问题(旁边无法使用)。

实际上,如果它不安全,每次调用pthread_cancel都必须通过检查线程是否存活(并确保它保持活动直到你取消它)而变得非常复杂。一个简单的“你还在那里”不会做。

总之,如果线程已经终止,我相信pthread_cancel 必须是安全的。当然,对于已终止和加入的线程,情况可能并非如此。

答案 1 :(得分:7)

a hint actually:

  

错误顶部

  ESRCH  No thread with the ID thread could be found.

MKS gives a bit other description:

  

ESRCH

     

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

OpenGroup recommends:

  

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

更新

在NPTL中有一个check for double cancel or cancel after exit:

  /* 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;

因此,退出后的第二次取消或取消将是死线的呐喊。

exiting_bitmask由__do_cancel:

设置
/* 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);

__ do_cancel既反应async cancel又反映to pthread_exit

void
__pthread_exit (value)
     void *value;
{
  THREAD_SETMEM (THREAD_SELF, result, value);

  __do_cancel ();

答案 2 :(得分:4)

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

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

答案 3 :(得分:0)

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

#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)