一个thread中,处于完全封闭的环境,没有任何代码出口,呵呵,pthread_cancel的做法就值得怀疑了,安全吗?
我一直坚持认为pthread_cancel是个危险的函数,如果在代码中遇到需要停止thread的流程,我都要在thread的代码中预留一个标记以便thread的退出:
while(1)
{
if( thread_stop == 1 )
{
pthread_exit(0);
}
}
强烈建议thread的出口使用pthread_exit(), 不要简单的使用return,这二者之间对于代码现场的清理是不同的
上面有些道理。不过当
while(1)
{
if( thread_stop == 1 )
{
...//含阻塞的业务过程
pthread_exit(0);
}
}
如果持续阻塞,thread_stop 没法检查退出!
另外thread的封闭性有 pthread_cleanup_xx 来作些处理:Cleanup handlers are functions that get called when a thread termi- nates, either by calling pthread_exit(3) or !!! because of cancellation !!!.
通常我是配合用,应该没有问题的。
实验了一下,
Fedora Core 6 上, 以下的代码就可以search线程是可以被cancel的.
如果要设置正确的CANCEL POINT, 用PTHREAD_CANCEL_DISABLE, PTHREAD_CANCEL_ENABLE就可以了.
FreeBSD 8.0-CURRENT上, 必须加上条件编译的部分, search线程才可以被cancel.
即必须PTHREAD_CANCEL_ENABLE加pthread_testcancel.
结论是:
Fedora Core 6 上
新线程是PTHREAD_CANCEL_ENABLE的,pthread_cancel时只要PTHREAD_CANCEL_ENABLE, 马上就被cancel了.
FreeBSD上
新线程是PTHREAD_CANCEL_ENABLE的,pthread_cancel需要PTHREAD_CANCEL_DISABLE 加pthread_testcancel()才能cancel.
看起来似乎Fedora Core 6的pthread_cancel是通过信号实现的, 新线程是PTHREAD_CANCEL_ENABLE的,即信号未被捕获((还是继承父线程的属性?));
而FreeBSD的pthread_cancel是通过函数pthread_testcancel实现的(检查PTHREAD_CANCEL_ENABLE是否被设置), 新线程是PTHREAD_CANCEL_DISABLE的(还是继承父线程的属性?).
int pthread_cancel(pthread_t thread)
发送终止信号给thread线程,如果成功则返回0,否则为非0值。发送成功并不意味着thread会终止。
int pthread_setcancelstate(int state, int *oldstate)
设置本线程对Cancel信号的反应,state有两种值:PTHREAD_CANCEL_ENABLE(缺省)和PTHREAD_CANCEL_DISABLE,分别表示收到信号后设为CANCLED状态和忽略CANCEL信号继续运行;old_state如果不为NULL则存入原来的Cancel状态以便恢复。
int pthread_setcanceltype(int type, int *oldtype)
设置本线程取消动作的执行时机,type有两种取值:PTHREAD_CANCEL_DEFFERED和PTHREAD_CANCEL_ASYNCHRONOUS,仅当Cancel状态为Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出和立即执行取消动作(退出);oldtype如果不为NULL则存入运来的取消动作类型值。
void pthread_testcancel(void)
检查本线程是否处于Canceld状态,如果是,则进行取消动作,否则直接返回。