线程在创建后,除了调用pthread_exit()主动退出,还可以被其它线程/任务通过pthread_cancel()来退出,这种机制叫做cancellation
代码语言:javascript复制/*
* 向<thread>发送一个cancellation请求.
* 根据线程的不同设置,
* 线程可能忽略这个请求,
* 或立即终止,
* 或推迟到下一个cancellation point再终止.
*
* 线程终止时, 执行的操作类似于pthread_exit(), 不过返回值为'PTHREAD_CANCELED'.
*/
int pthread_cancel
(
pthread_t thread
);
新创建的线程,默认就支持cancellation。其状态可以使用pthread_setcancelstate()来修改
代码语言:javascript复制/*
* 将线程的cancellation状态设置为<state>,
* 如果<oldstate>非NULL, 返回之前的状态.
*
* 状态值二选一:
* PTHREAD_CANCEL_ENABLE
* PTHREAD_CANCEL_DISABLE
*
* 新线程的默认状态为PTHREAD_CANCEL_ENABLE
*/
int pthread_setcancelstate
(
int state,
int *oldstate
);
这个cancellation类型有两种,通过pthread_setcanceltype()设置
代码语言:javascript复制/*
* 将线程的cancellation类型设置为<type>,
* 如果<oldtype>非NULL, 返回之前的类型.
*
* 类型值二选一:
* PTHREAD_CANCEL_ASYNCHRONOUS - 立即执行收到的cancellation请求
* PTHREAD_CANCEL_DEFERRED - 下一个cancellation point再执行cancellation
*
* 新线程的默认类型为PTHREAD_CANCEL_DEFERRED
*/
int pthread_setcanceltype
(
int type,
int *oldtype
);
如何添加cancellation point呢?可以使用pthread_testcancel()
代码语言:javascript复制/*
* 为当前线程创建一个cancellation point.
*
* 如果已经enable cancellation,
* 并且cancellation类型是PTHREAD_CANCEL_DEFERRED,
* 并且已经收到cancellation请求,
* 则调用pthread_exit()并返回'PTHREAD_CANCELED'.
*/
void pthread_testcancel();
那为什么第一个例子里的sleep()也可以cancel呢?是因为OS的一些API使用了一个pthread_testandset_canceltype()
代码语言:javascript复制/*
* 相当于先执行pthread_testcancel(), 再执行pthread_setcanceltype().
*/
int pthread_testandset_canceltype
(
int type,
int *oldtype
);
都有哪些呢
库 | 函数 |
---|---|
aioPxLib | aio_suspend() |
ioLib | creat(), open(), read(), write(), close(), fsync(), fdatasync() |
mqPxLib | mq_receive(), mq_send() |
pthreadLib | pthread_cond_timedwait(), pthread_cond_wait(), pthread_join(), pthread_testcancel() |
semPxLib | sem_wait() |
sigLib | pause(), sigsuspend(), sigtimedwait(), sigwait(), sigwaitinfo() |
timerLib | sleep(), nanosleep() |
cancellation这种行为,线程本身很难预测,因此线程使用的一些系统资源就无法按照正常退出的流程去释放。这种情况,可以使用pthread_cleanup_push()来注册一些清理函数。而在正常退出之前,可以使用pthread_cleanup_pop()将其取消
代码语言:javascript复制/*
* 添加cancellation清理函数<routine>.
* 线程退出时, 按照添加顺序的倒叙、使用参数<arg>执行.
*/
void pthread_cleanup_push
(
void (*routine)(void *),
void *arg
);
/*
* 删除最后添加的清理函数.
* 如果<run>非0, 则执行它.
*/
void pthread_cleanup_pop
(
int run
);