pthread_exit(PTHREAD_CANCELED)和pthread_cancel(pthread_self())之间的区别。

问题描述 投票:1回答:3

当调用pthread_exit(PTHREAD_CANCELED)时,我有预期的行为(堆栈释放,destructors调用),但线程_cancel(pthread_self())只是终止了线程。

为什么pthread_exit(PTHREAD_CANCELED)和pthread_cancel(pthread_self())有很大的不同,而且在后一种情况下线程内存没有被释放?

背景如下。

从信号处理程序中调用,这种奇怪的方法背后的原因是取消一个线程,等待外部库semop()完成(我想是在EINT上循环)。

我注意到,从其他线程调用pthread_cancel不工作(好像semop不是一个取消点),但给线程发信号然后调用pthread_exit可以工作,但会在信号处理程序中调用destructor.pthread_cancel可以将动作推迟到下一个取消点。

pthreads signals
3个回答
1
投票

从具体的线程清理行为来看,通过以下方式取消一个线程应该没有区别 pthread_cancel() 并通过 pthread_exit().

POSIX说:

[...]当注销被执行时,应调用线程的注销清理处理程序。当最后一个注销清理处理程序返回时,应调用线程特有的数据析构函数。当最后一个destructor函数返回时,线程应被终止。


从Linux的 man pthread_cancel:

当取消请求被执行时,线程会发生以下步骤(按此顺序)。

  1. 取消清理处理程序被弹出(与被推送的顺序相反)并被调用。 参见pthread_cleanup_push(3)。

  2. 线程特定的数据分解器会被调用,顺序未定。 参见pthread_key_create(3)。

  3. 线程被终止。 参见pthread_exit(3))。


参照通过给线程发信号来引入取消点的策略,我怀疑这是最干净的方式。

因为很多系统调用在接收到信号时都会返回,设置了 errnoEINTR在这种情况下,很容易抓住这种情况,只需让线程在这种条件下干净利落地结束自己的生命。pthread_exit().

所以,一些伪代码。

while (some condidtion) 
{
  if (-1 == semop(...))
  { /* getting here on error or signal reception */
    if (EINTR == errno)
    { /* getting here on signal reception */
      pthread_exit
    }
  }
}

1
投票

结果发现没有区别 然而一些有趣的副作用发生了。

std::iostream 特别是cerrcout包括取消点。当底层操作被取消时,流被标记为不好。所以,如果只有一个线程在试图打印时发现了取消,你将得不到任何其他线程的输出。

所以玩 pthread_setcancelstate()pthread_testcancel() 或者直接打电话 cerr.clear() 当需要的时候。

只适用于C++流,stderr,stdin似乎不受影响。


1
投票

首先,有两个与线程相关联的东西会告诉你调用pthread_cancel()时该怎么做。

1. pthread_setcancelstate
2. pthread_setcanceltype

第一个函数会告诉你这个线程是否可以被取消,第二个函数会告诉你这个线程应该在什么时候以及如何被取消,例如,是在你发出取消请求后立即终止这个线程,还是需要等到这个线程达到某个里程碑后才被终止。

当你调用pthread_cancel()时,线程不会直接被终止,而是会执行以上两个动作,即检查该线程是否可以被取消,如果可以,则何时取消。

如果你禁用了取消状态,那么pthread_cancel()就不能终止该线程,但取消请求会留在队列中等待该线程成为可取消状态,也就是说,如果你启用了取消状态,那么在某个时间点,你的取消请求就会开始终止该线程。

而如果你使用pthread_exit(),那么无论线程的取消状态和取消类型如何,线程都会被终止。

*这是pthread_exit()和pthread_cancel()的区别之一,还有更多的区别。

© www.soinside.com 2019 - 2024. All rights reserved.