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

时间:2014-01-14 14:41:48

标签: pthreads signals

当调用pthread_exit(PTHREAD_CANCELED)时,我有预期的行为(堆栈展开,析构函数调用)但是 thread_cancel(pthread_self())刚刚终止了线程。

为什么pthread_exit(PTHREAD_CANCELED)和pthread_cancel(pthread_self())显着不同,并且在后一种情况下不释放线程内存?

背景如下:

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

我注意到从其他线程调用pthread_cancel不起作用(好像semop不是取消点)但是发信号通知线程然后调用pthread_exit但是在信号处理程序中调用析构函数。 pthread_cancel可以将动作推迟到下一个取消点。

3 个答案:

答案 0 :(得分:1)

就线程特定的清理行为而言,通过pthread_cancel()取消线程和通过pthread_exit()退出线程之间应该没有区别。

POSIX says

  

[...]当取消操作时,应调用线程的取消清除处理程序。当最后一个取消清除处理程序返回时,应为线程调用特定于线程的数据析构函数。当最后一个析构函数返回时,线程将被终止。


来自Linux的man pthread_cancel

  

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

     
      
  1. 弹出取消清理处理程序(与它们被按下的顺序相反)并调用。 (见pthread_cleanup_push(3)。)

  2.   
  3. 以未指定的顺序调用特定于线程的数据析构函数。 (见pthread_key_create(3)。)

  4.   
  5. 线程终止。 (见pthread_exit(3)。)

  6.   

参考策略通过发信号通知一个取消点,我怀疑这是最干净的方式。

当接收到信号设置errnoEINTR时,许多系统调用都会返回,很容易发现这种情况,只需让线程通过pthread_exit()在这种情况下干净利落地结束自己

Soem pseudoie代码:

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

答案 1 :(得分:1)

首先,与线程相关的两件事将告诉您在调用pthread_cancel()时该怎么做。

1. pthread_setcancelstate
2. pthread_setcanceltype

第一个函数将告诉您该特定线程是否可以取消,第二个函数告诉您何时和如何取消该线程,例如,是否应在发送取消请求后立即终止该线程,或者需要等到该线程达到某个里程碑后再终止。

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

如果禁用取消状态,则pthread_cancel()无法终止该线程,但是取消请求将保留在队列中,等待该线程变为可取消状态,即在某个时间点,如果您启用取消状态,那么您的取消请求将开始终止该线程

如果使用pthread_exit(),则该线程将终止,而与该特定线程的取消状态和取消类型无关。

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

答案 2 :(得分:0)

原来没有区别。 然而,发生了一些有趣的副作用。

std::iostream上的操作尤其是cerr / cout包括取消点。取消基础操作时,流被标记为不好。因此,如果只有一个线程在尝试打印时发现取消,那么您将不会从任何其他线程获得输出。

请与pthread_setcancelstate()pthread_testcancel()一起玩,或在需要时致电cerr.clear()

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