linux多线程相关的API-(3)--线程取消cancel与清理push/pop

1、pthread_cancel(pthread_t tid);

功能描述:向线程号为tid的线程发送一个取消运行的请求。线程tid是不是真的会被取消?何时会被取消?这两个问题依赖于本线程的两个控制属性:是否取消依赖于一个状态使能标志stat、何时取消依赖于一个类型标志type。

pthread_setcancelstate函数可以设置状态为使能enable或者不使能disable(一个线程创建后的默认状态为使能)。如果设置为非使能,那么pthread_cancel发出的取消请求,仍然会被插入请求队列,一旦stat标志被改为使能,线程仍可以收到这个取消请求;如果stat设置为使能,那么pthread_cancel发出的取消请求会立即被线程接收到。收到取消请求以后,何时执行取消,这就得继续看type属性了。

pthread_setcanceltype函数可以设置线程的type属性,可设置的值为:异步取消asynchronous、延迟取消deferred(一个线程创建后的默认type为deferred)。异步取消,指的是只要执行了pthread_cancel函数,那么本线程就应该会被立即取消(“应该”这个词的意思是,内核并不能100%保证能够立即取消,但是内核会尽快的取消它)。如果type被设置为defered,那么本线程将会在下一个取消点被取消。下面这几个函数被称为取消点:
pthread_join()、 pthread_testcancel()、pthread_cond_wait()、 pthread_cond_timedwait()、sem_wait()、sigwait()。

当取消请求开始响应之后,内核会自动执行下面的步骤:
① pthread_cleanup_push压入的函数将会被倒序执行一遍;
② 调用线程数据的析构函数(更多细节请参考pthread_key_create函数)

③ 线程真正结束(更多细节请参考pthread_exit函数)

使用pthread_join函数可以读取到线程的退出状态为:PTHREAD_CANCELED。

返回值:成功返回0,失败返回非0

2、void pthread_cleanup_push(void (*routine)(void *), void *arg);

3、void pthread_cleanup_pop(int execute);

这两个函数在linux中是用含左右{}的宏实现的,所以,这两个函数必须成对出现,且必须处于同一级别的代码中。
功能描述:注册一些函数routine到一个队列中,当线程被取消后,这些函数会按照被注册的相反顺序,以本函数的形参arg作为实参,被执行一遍。注册的这些函数有啥作用?一个典型的应用方法比如:解锁一个互斥锁。

本函数的亲兄弟函数pthread_cleanup_pop,会把注册到队列中的函数,队列最前面的那个给删掉,是否要执行以下这个删掉的函数,依赖于pthread_cleanup_pop的实参execute,0为不执行,非0为执行。

当线程执行pthread_cancel后,且真正开始响应取消请求后,会发生下述动作:
① 当按照队列中注册的相反顺序,把注册的函数带arg参数执行一遍;
② 如果用pthread_exit函数来终止线程,那么队列中注册的函数也会被执行;如果在线程的启动函数中,用return语句来终止线程,那么这些注册的函数将不会被执行!
③ 当调用pthread_cleanup_pop函数,且带非0实参,那么最后注册的一个函数会从队列中被移除,然后被立即执行一次。

应用实例:https://blog.csdn.net/caianye/article/details/5912172

pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut);
pthread_mutex_lock(&mut);
/* do some work */
pthread_mutex_unlock(&mut);
pthread_cleanup_pop(0);

本来do some work之后是有pthread_mutex_unlock(&mut);这句,也就是有解锁操作,但是在do some work时会出现非正常终止,那样的话,系统会根据pthread_cleanup_push中提供的函数,和参数进行解锁操作或者其他操作,以免造成死锁!


猜你喜欢

转载自blog.csdn.net/qq_31073871/article/details/80984596