当调用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可以将动作推迟到下一个取消点。
答案 0 :(得分:1)
就线程特定的清理行为而言,通过pthread_cancel()
取消线程和通过pthread_exit()
退出线程之间应该没有区别。
[...]当取消操作时,应调用线程的取消清除处理程序。当最后一个取消清除处理程序返回时,应为线程调用特定于线程的数据析构函数。当最后一个析构函数返回时,线程将被终止。
来自Linux的man pthread_cancel
:
当请求取消被执行时,线程会发生以下步骤(按此顺序):
弹出取消清理处理程序(与它们被按下的顺序相反)并调用。 (见pthread_cleanup_push(3)。)
以未指定的顺序调用特定于线程的数据析构函数。 (见pthread_key_create(3)。)
- 醇>
线程终止。 (见pthread_exit(3)。)
参考策略通过发信号通知一个取消点,我怀疑这是最干净的方式。
当接收到信号设置errno
到EINTR
时,许多系统调用都会返回,很容易发现这种情况,只需让线程通过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似乎不受影响。