POSIX之cancel

2022-12-05 15:55:36 浏览数 (2)

线程在创建后,除了调用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
    );

0 人点赞