关于pthread_cancel函数的运用
一、相关简介
1、取消点:
我们都知道,程序的进行是一个时间过程而不是一个时间点。取消点的简单意思来说:
在一个时间段内,程序被挂起时,可以被取消的一个时间点。(APUE363页有详细的取消点函数)
也就是说,当线程出现 block(阻塞) 时,这个被阻塞的地方就是可被取消的地方。
更通俗的来说:就是线程A执行过程中,如果遇到其他线程B执行cancel函数,
线程继续运行,直到线程某一行代码出现阻塞
(如:pthread_testcancel、pthread_join、pthread_cond_wait、printf、sleep、read、write、等都是可以产生阻塞的函数)
此时就会退出。如果线程B还使用了pthread_join去获取返回值,返回值为整型且为PTHREAD_CANCELED(-1)
2、cancelstate
上诉的第3个函数pthread_setcancelstate是可以改变线程遇到cancel信号的状态。
一共有两种状态:
1、对cancel信号有反应(默认)
2、不理会cancel信号
3、canceltype
上诉第4个函数pthread_setcanceltype是可以改变线程终止类型
前提是cancelstate为enable
也是一共两个状态:
1、等到取消点再终止。(默认)
2、直接终止。
二、有关函数
1、线程创建函数 create
@thread:
线程标识符
@attr:
线程属性,传递NULL为默认属性
@start_routine:
建立的新线程的函数指针
@arg:
线程的参数
return:
成功返回0,错误返回errno,且thread不定义
EAGAIN:资源不足创建新线程
EINVAL:输入无效的线程属性
EPERM:无权限设置调度策略和线程属性参数即attr
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
2、线程终止函数 cancel
@thread:
需要终止的线程标识号
return:
成功返回0 错误返回errno
ESRCH:错误的线程号
int pthread_cancel(pthread_t thread);
默认情况下,使用cancel函数后,线程并不会立刻终止。在关闭一个线程中,有两个重要的点是:
3、线程终止状态 cancelstate
@state:
PTHREAD_CANCEL_ENABLE:
线程对cancel信号立即有反应,将设置为CANCEL状态 (默认)
PTHREAD_CANCEL_DISABLE:
如果线程state为不可取消,线程不理会信号,继续执行,而使用cancel函数的线程会一直阻塞到可取消状态
@oldstate:
NULL:state写入有效,即当前只想设置属性,而不关心原来的属性
不为NULL:state不写入,保持原有的设定,且获取原来的属性
return:
成功返回0,错误返回errno
EINVAL:无效的state
int pthread_setcancelstate(int state,int *oldstate)
4、线程终止类型 canceltype
@type:
PTHREAD_CANCEL_DEFERRED:
运行到下一个取消点就退出 (默认)
PTHREAD_CANCEL_ASYNCHRONOUS:
直接退出
@oldtyoe:
NULL:type写入有效,即当前只想设置属性,而不关心原来的属性
不为NULL:type不写入,保持原有的设定,且获取原来的属性
return:
成功返回0,错误返回errno
EINVAL:无效的type
int pthread_setcanceltype(int type,int *oldtype)
三、实践
有了上一章的简介,现在来实际操作一下。
1、全部默认
(1)no cancel
线程:
void *pt1(void*p)
{
int *num=p;
while(--(*num)>100)if(*num==1000)printf("block\n");
return NULL;
}
main函数:
void main(void)
{
int val=65535;
pthread_t p1;
pthread_create(&p1,NULL,pt1,&val);
pthread_join(p1,NULL);
printf("join p1:%d\n",val );
}
输出:当 *num等于1000时打印阻塞,但是线程继续执行到 *num=100
block
join p1:100
(2)cancel
在创建进程后立刻cancel掉进程,由于进程运行速度过快,添加了一些运算减缓线程运行速度。
线程:
void *pt1(void*p)
{
int *num=p;
while(--(*num)>100)if(*num==1000)printf("block\n");
return NULL;
}
main:
void main(void)
{
int val=65535;
pthread_t p1;
pthread_create(&p1,NULL,pt1,&val);
pthread_cancel(p1);
pthread_join(p1,NULL);
printf("join p1:%d\n",val );
}
输出:当 *num==1000时,打印信息产生阻塞,也就是取消点为printf函数,线程在此时退出
block
join p1:1000
2、state设置
state==PTHREAD_CANCEL_DISABLE
线程:
void *pt1(void*p)
{
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
int *num=p;
while(--(*num)>100)if(*num==1000)printf("block\n");
return NULL;
}
main:
void main(void)
{
int val=65535;
pthread_t p1;
pthread_create(&p1,NULL,pt1,&val);
pthread_cancel(p1);
pthread_join(p1,NULL);
printf("join p1:%d\n",val );
}
输出结果与无cancel相同,线程不理会cancel信号、
3、type设置
前提都是state为enable状态
type==PTHREAD_CANCEL_ASYNCHRONOUS
void *pt1(void*p)
{
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
int *num=p;
while(--(*num)>100)if(*num==1000)printf("block\n");
return NULL;
}
main:
void main(void)
{
int val=65535;
pthread_t p1;
pthread_create(&p1,NULL,pt1,&val);
pthread_cancel(p1);
pthread_join(p1,NULL);
printf("join p1:%d\n",val );
}
输出:type修改为异步类型,只要收到cancel信号,立马结束线程
多种可能 取决于运行速度
join p1:34474
join p1:29783
join p1:39144