【linux系统编程学习笔记】第十节:线程的取消机制(杀死线程)(pthread_cancel 取消线程、pthread_cleanup_push 、pthread_cleanup_pop)
·
取消机制——杀死线程
pthread_setcancelstate 设置线程的取消状态
pthread_setcanceltype 设置线程相应取消命令方式
pthread_cleanup_push 注册线程退出处理函数
pthread_cleanup_pop 清除注册的退出处理函数
线程的取消机制概念
所谓先线程的取消机制就是杀死一个线程,跟我们进程当中的异步信号有点相似,在我们的程序中,我们可以给某个指定的线程发送取消指令,当这个线程收到这条取消指令之后,便会退出这条线程,我们把这种机制,称为线程的取消机制。
取消机制相关API
pthread_cancel 取消线程
#include <pthread.h>
int pthread_cancel(pthread_t thread);
函数功能:
线程也可以选择不被取消指令所取消,这需要使用到取消状态函数
pthread_setcancelstate 设置线程的取消状态
#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
pthread_setcanceltype 设置线程相应取消命令方式
#include <pthread.h>
int pthread_setcanceltype(int type, int *oldtype);
函数功能:
取消点函数:


线程取消机制的完善
由于线程是可以被取消(杀死),而且是异步的操作(你不知道什么时候会接收到线程的取消指令),从而导致我们再线程的操作当中容易出现逻辑漏洞(类似于死锁等等),所以我们诞生一种包裹机制,可以在进行某部分逻辑操作的时候,为了防止线程被异步杀死所出现的漏洞,在线程取消之前先去做好一些动作,也就是线程退出处理函数(类似于进程调用exit退出前可以去运行atexit或者是on_exit两个注册的退出处理函数)。
完善取消机制相关API
pthread_cleanup_push 注册线程退出处理函数
pthread_cleanup_pop 清除注册的退出处理函数
#include <pthread.h>
void pthread_cleanup_push(void (*routine)(void *),void *arg);
void pthread_cleanup_pop(int execute);
- pthread_cleanup_push:注册一个收到取消指令后的线程退出处理函数,用于执行该函数过后,如果接收到线程的取消指令,则先去执行该函数所注册的函数后,才能退出线程
- pthread_cleanup_pop:必须与上面的函数配套使用,用于清除出注册的函数,代表以后接收到取消指令我们也不会去执行注册的函数
- routine:这个是传输给routine这个函数指针的函数的参数
- arg:原本设置的取消指令的响应类型,他会存放到这个内存中,可以设置为NULL
- execute:如果该值为0,则清除出注册函数,而不去执行注册函数的内容,如果该值为非0,则清除出注册函数的同时,去运行注册函数的内容
例程:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
pthread_t tid;//线程ID
//注册的线程退出处理函数
void routine(void *arg)
{
printf("嘻嘻 arg=%s\n", (char *)arg);
}
void *thread(void *arg)
{
int i, j, z=5;
//设置线程不能被pthread_cancel所杀死
// pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
//设置线程一旦有人对线程发送取消请求则马上退出线程,不用遇到取消点函数
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
//在线程被取消的时候,要求在退出线程之前执行routine里面的内容,"哈哈"则是传输给routine的参数
pthread_cleanup_push(routine, "哈哈");
//因为sleep是取消点函数,所以采用消耗CPU的方式来延时
while(z--)
{
for( i=100000; i>0; i--)
for( j=10000; j>0; j--);
printf("in thread\n");
}
//将pthread_cleanup_push所声明如果取消线程时执行的routine函数清除出去,
//0代表清楚而不执行,非0代表清楚且执行一下pthread_cleanup_push所注册的routine函数里面的内容
pthread_cleanup_pop(0);
z=5;
while(z--)
{
for( i=100000; i>0; i--)
for( j=10000; j>0; j--);
printf("next thread\n");
}
return NULL;
}
void sighand(int signum)
{
//给指定线程发送取消请求,线程遇到取消点函数才会退出
pthread_cancel(tid);
}
int main(void)
{
int retval;
//设置信号响应函数
signal(SIGINT, sighand);
//创建子线程
pthread_create(&tid, NULL, thread, NULL);
//等待回收子线程
retval = pthread_join(tid, NULL);
if(retval != 0)
{
fprintf(stderr, "join failed :%s\n", strerror(retval));
return -1;
}
printf("join success\n");
return 0;
}
图片来之——《Linux环境编程图文指南》林世霖
更多推荐

所有评论(0)