文章目录
- Linux系统线程
- 一、线程
- 二、线程API
- 三、线程属性
- 1.线程属性变量的使用步骤:
- 2.获取、设置线程分离属性pthread_attr_setdetachstate\pthread_attr_getdetachstate
- 3.获取、设置线程是否继承创建者的调度策略pthread_attr_setinheritsched\pthread_attr_getinheritsched
- 4.获取设置线程的调度策略(线程调度方式)pthread_attr_setschedpolicy\pthread_attr_getschedpolicy
- 5.获取、设置线程静态优先级pthread_attr_setschedparam\pthread_attr_getschedparam
- 6.获取、设置动态优先级nice
- 7.获取、设置栈大小和警戒区大小
- 8.退出线程pthread_exit\接合指定线程pthread_join\pthread_tryjoin_np
- 9.线程取消pthread_cancel
- 10.设置和获取线程的取消状态和取消类型pthread_setcancelstate\pthread_setcanceltype
Linux系统线程
一、线程
1.线程的引入
由于进程的地址空间是私有的,因此系统开销比较大,当有很多相同资源被多个进程使用的时候,系统内存占用比较大,为了提高系统运行程序的性能,调高任务切换的效率,引入轻量级进程的概念,这个就是线程。
2.线程和进程的区别
进程是系统资源分配的基本单位
线程是系统任务调度的基本单位
3.线程的资源
①、一个进程可以有多个线程,共享以下资源:
(1)静态数据
(2)进程中打开的文件描述符
(3)信号处理函数
(4)当前路径
(5)可执行指令
(6)用户ID和用户组ID
②、不可共享(线程私有资源)
(1)线程ID
(2)程序计数器和相关的寄存器
(3)线程任务函数里面的局部变量
(4)错误码:errno
(5)信号掩码
(6)线程执行的状态和线程属性
二、线程API
线程相关函数不属于标准C库,编译多线程代码的时候,需要链接线程库pthread
1.线程创建pthread_create
功能
创建一条新线程
头文件
#include <pthread.h>
原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void*(*start_routine) (void*), void *arg);
参数
thread 新线程的TID
attr 线程属性
start_routine 线程例程
arg 线程例程的参数
返回值
成功 0 失败 errno
对此函数的使用需要知道以下几点:
1,线程例程指的是:如果线程创建成功,那么该线程会立即去执行的函数。
2,POSIX 线程库的所有 API 对返回值的处理原则都是一致的:成功返回 0,失败返回错误码 errno。
3,线程属性如果为 NULL,则会创建一个标准属性的线程,线程的属性非常多
void *(*start_routine) (void *) 线程例程函数
线程任务函数:需要自己定义
void *start_routine (void *)
{
//函数体
}
2.跟线程属性有关的 API 有:
pthread_attr_destroy( ) 销毁线程属性
pthread_attr_getaffinity_np( ) 获取 CPU 亲和度
pthread_attr_getdetachstate( ) 获取分离属性
pthread_attr_getguardsize( ) 获取栈警戒区大小
pthread_attr_getinheritsched( ) 获取继承策略
pthread_attr_getschedparam( ) 获取调度参数
pthread_attr_getschedpolicy( ) 获取调度策略
pthread_attr_getscope( ) 获取竞争范围
pthread_attr_getstack( ) 获取栈指针和栈大小
pthread_attr_getstacksize( ) 获取栈大小
pthread_attr_init( ) 初始化线程属性
pthread_attr_setaffinity_np( ) 设置 CPU 亲和度
pthread_attr_setdetachstate( ) 设置分离属性
pthread_attr_setguardsize( ) 设置栈警戒区大小
pthread_attr_setinheritsched( ) 设置继承策略
pthread_attr_setschedparam( ) 设置调度参数
pthread_attr_setschedpolicy( ) 设置调度策略
pthread_attr_setscope( ) 设置竞争范围
pthread_attr_setstack( ) 设置栈的位置和栈大小(慎用)
pthread_attr_setstacksize( ) 设置栈大小
3.线程的结合属性pthread_join\pthread_tryjoin_np
功能
接合指定线程
头文件
#include <pthread.h>
原型
int pthread_join(pthread_t thread, void**retval);
int pthread_tryjoin_np(pthread_t thread, void**retval);
参数
thread 线程TID
retval 储存线程退出值的内存的指针
返回值
成功 0 失败 errno
注意:
1,如果线程退出时没有退出值,那么 retval 可以指定为 NULL。
2,pthread_join( )指定的线程如果尚在运行,那么他将会阻塞等待。
3,pthread_tryjoin_np( )指定的线程如果尚在运行,那么他将会立即出错返回。
4,使用pthread_tryjoin_np( )这个函数,直接编译,出现隐式声明警告
-
编译的时候,加上-D _GNU_SOURCE
-
or直接在代码的第一行加上 #define _GNU_SOURCE这个宏定义
4.取消请求pthread_cancel
功能
给指定线程发送一个取消请求
头文件
#include <pthread.h>
原型
int pthread_cancel(pthread_t thread);
参数.
thread 线程TID
返回值
成功 0 失败 errno
三、线程属性
(1)、分离属性 默认接合
(2)、调度策略 默认0静态优先级,非实时
(3)、栈大小和警戒区大小 默认8M和4kb
1.线程属性变量的使用步骤:
-
1,定义线程属性变量,并且使用 pthread_attr_init( )初始化。
-
2,使用 pthread_attr_setXXX( )来设置相关的属性。
-
3,使用 pthread_attr_getXXX( )来获取相关的属性。
-
4,使用该线程属性变量创建相应的线程。
-
5,使用 pthread_attr_destroy( )销毁该线程属性变量。
#include <pthread.h>
初始化线程属性变量
int pthread_attr_init(pthread_attr_t *attr);
销毁
int pthread_attr_destroy(pthread_attr_t *attr);
2.获取、设置线程分离属性pthread_attr_setdetachstate\pthread_attr_getdetachstate
功能
获取、设置线程的分离属性
头文件
#include <pthread.h>
原型
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
参数
attr 线程属性变量
detachstate
PTHREAD_CREATE_DETACHED 分离
PTHREAD_CREATE_JOINABLE 接合
返回值
成功 0 失败 errno
备注
线程缺省的状态是接合的,[默认是接合]
一条线程如果是可接合的,意味着这条线程在退出时不会自动释放自身资源,而会成为僵尸线程,同时意味着该线程的退出值可以被其他线程获取。
因此,如果不需要某条线程的退出值的话,那么最好将线程设置为分离状态,以保证该线程不会成为僵尸线程。
test
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <time.h>
#include <pthread.h>
void *func(void *arg)
{
int k = 0;
while(1)
{
printf("k = %d\n", k);
sleep(1);
k++;
if (k == 3)
{
break;
}
}
}
int main(int argc, char const *argv[])
{
pthread_t pid;
//设置线程的分离属性
pthread_attr_t attr;
//初始化线程的分离属性
pthread_attr_init(&attr);
//获取线程的分离属性
int act;
pthread_attr_getdetachstate(&attr, &act);
if (act == PTHREAD_CREATE_DETACHED)
{
printf("分离属性\n");
}
if (act == PTHREAD_CREATE_JOINABLE)
{
printf("接和属性\n");
}
// pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//设置分离属性,原先默认是接合
pthread_create(&pid, &attr, func, NULL);
pthread_join(pid, NULL);
return 0;
}
3.获取、设置线程是否继承创建者的调度策略pthread_attr_setinheritsched\pthread_attr_getinheritsched
功能
获取、设置线程是否继承创建者的调度策略
头文件
#include <pthread.h>
原型
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);
int pthread_attr_getinheritsched(pthread_attr_t *attr, int *inheritsched);
参数
attr 线程属性变量
inheritsched
PTHREAD_INHERIT_SCHED 继承创建者的调度策略
PTHREAD_EXPLICIT_SCHED 使用属性变量中的调度策略
返回值
成功 0 失败 errno
默认是[PTHREAD_INHERIT_SCHED 继承创建者的调度策略]
test
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <time.h>
#include <pthread.h>
void *func(void *arg)
{
int k = 0;
while(1)
{
printf("k = %d\n", k);
sleep(1);
k++;
if (k == 3)
{
break;
}
}
}
int main(int argc, char const *argv[])
{
pthread_t pid;
//设置线程的分离属性
pthread_attr_t attr;
//初始化线程的分离属性
pthread_attr_init(&attr);
//获取调度策略
int act;
pthread_attr_getinheritsched(&attr, &act);
if (act == PTHREAD_INHERIT_SCHED)
{
printf("继承创建者的调度策略\n");
}
if (act == PTHREAD_EXPLICIT_SCHED)
{
printf("使用属性变量中的调度策略\n");
}
// pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
int po;
pthread_attr_getschedpolicy(&attr, &po);
if (po == SCHED_FIFO)
{
printf("以先进先出的排队方式调度\n");
}
if (po == SCHED_RR)
{
printf("以轮转的方式调度\n");
}
if (po == SCHED_OTHER)
{
printf("非实时调度的普通线程\n");
}
pthread_create(&pid, NULL, func, NULL);
return 0;
}
4.获取设置线程的调度策略(线程调度方式)pthread_attr_setschedpolicy\pthread_attr_getschedpolicy
功能
获取、设置线程的调度策略
头文件
#include <pthread.h>
原型
int pthread_attr_setschedpolicy(pthread_attr_t *att, int policy);
int pthread_attr_getschedpolicy(pthread_attr_t *attr, int *policy);
参数
attr 线程属性变量
policy
SCHED_FIFO 以先进先出的排队方式调度
SCHED_RR 以轮转的方式调度
SCHED_OTHER 非实时调度的普通线程
返回值
成功 0 失败 errno
备注
默认:[SCHED_OTHER 非实时调度的普通线程]
SCHED_FIFO 以先进先出的排队方式调度
以排队的方式来调度线程,谁先进去,谁就先执行,但如果有一个优先级比排队的线程优先级要高,那么就会跟在这个最高优先级的线程的后面去执行
SCHED_RR 以轮转的方式调度
以排队的方式来调度线程,但是是随机去调度任务在执行的
SCHED_OTHER 非实时调度的普通线程
1,当线程的调度策略为 SCHED_FIFO 时,其静态优先级(static priority)必须设置为1-99,这将意味着一旦这种线程处于就绪态时,他能立即抢占任何静态优先级为 0 的普通线程。采用 SCHED_FIFO 调度策略的线程还遵循以下规则:
A) 当他处于就绪态时,就会被放入其所在优先级队列的队尾位置。
B) 当被更高优先级的线程抢占后,他会被放入其所在优先级队列的队头位置,当 所有优先级比他高的线程不再运行后,他就恢复运行。
C) 当他调用 sched_yield( )后,他会被放入其所在优先级队列的队尾的位置。
总的来讲,一个具有 SCHED_FIFO 调度策略的线程会一直运行直到发送 I/O 请求,或者被更高优先级线程抢占,或者调用 sched_yield( )主动让出 CPU。
2,当线程的调度策略为 SCHED_RR 时,情况跟 SCHED_FIFO 是一样的,区别在于:每一个 SHCED_RR 策略下的线程都将会被分配一个额度的时间片,当时间片耗光时,他会 被放入其所在优先级队列的队尾的位置。可以sched_rr_get_interval( )来获得时间片的具 体数值。
3,当线程的调度策略为 SCHED_OTHER 时,其静态优先级(static priority)必须设置 为 0。该调度策略是 Linux 系统调度的默认策略,处于 0 优先级别的这些线程按照所谓的动态优先级被调度,而动态优先级起始于线程的 nice 值,且每当一个线程已处于就绪态但被 调度器调度无视时,其动态优先级会自动增加一个单位,这样能保证这些线程竞争 CPU 的公平性。
注意:
当需要给一个线程设置调度方面的属性时,必须先将线程的 inheritsched 设置为
PTHREAD_EXPLICIT_SCHED
5.获取、设置线程静态优先级pthread_attr_setschedparam\pthread_attr_getschedparam
功能
获取、设置线程静态优先级
头文件
#include <pthread.h>
原型
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_ param *param);
int pthread_attr_getschedparam(pthread_attr_t *attr, struct sched_ param *param);
参数
attr 线程属性变量
param 静态优先级: 0到99
返回值
成功0 失败 errno
备注
0为默认的非实时普通进程
1-99为实时进程,数值越大,优先级越高
静态优先级是一个定义如下的结构体
struct sched_param
{
int sched_priority;
};
1.可见静态优先级就是一个只有一个整型数据的结构体,这个整型数值介于 0 到 99 之间,0 级线程被称为非实时的普通线程,他们之间的调度凭借所谓的动态优先级来博弈。而 1-99级线程被称为实时线程,他们之间的调度凭借他们不同级别的静态优先级和不同的调度策略(如果他们的静态优先级一样的话)来博弈
2.线程的静态优先级(static priority)之所以被称为“静态”,是因为只要你不强行
使用相关函数修改他,他不会随着线程的执行而发生改变,静态优先级决定了实时线程的基本调度次序,如果他们的静态优先级一样,那么调度策略再为调度器提供进一步的调度依据。
3,线程的动态优先级(dynamic prioriy)是非实时的普通线程独有的概念,之所以被称为“动态”,是因为它会随着线程的运行,根据线程的表现而发生改变,具体来讲是——如果一条线程是“CPU 消耗型”的,比如视频解码算法,这类线程只要一运行就黏住 CPU不放,这样的线程的动态优先级会被慢慢地降级,这符合我们的预期,因为这类线程不需要很高的响应速度,你只要保证一定的执行时间片就可以了。相反,另一类线程被称为“IO消耗型”,比如编辑器,这类线程绝大部分的时间都在睡眠,调度器发现每次调度他他都毅然决然地放弃了,将宝贵的 CPU 让给了其他线程,了不起是个大好人,因此会慢慢地提高他的动态优先级,使得这类线程在同等的非实时普通线程中,有越来越高的响应速度,表现出更好的交互性能,这也正是我们想要的结果。
4.线程的优先级分为静态和动态两种,静态优先级数值越大,优先级越高,动态优先级数据越小,优先级越高,看一个线程谁先被执行,查看静态优先级的数值,查看动态优先级的数值
test
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <time.h>
#include <pthread.h>
void *func(void *arg)
{
int k = 0;
while(1)
{
printf("k = %d\n", k);
sleep(1);
k++;
if (k == 3)
{
break;
}
}
}
void *func1(void *arg)
{
int l = 0;
while(1)
{
printf("l = %d\n", l);
sleep(1);
l++;
if (l == 3)
{
break;
}
}
}
int main(int argc, char const *argv[])
{
pthread_t pid;
pthread_t pid1;
//设置线程的分离属性
pthread_attr_t attr;
pthread_attr_t attr1;
//初始化线程的分离属性
pthread_attr_init(&attr);
pthread_attr_init(&attr1);
//获取静态优先级
struct sched_param sc;
struct sched_param sc1;
// pthread_attr_getschedparam(&attr, &sc);
// printf("sc.sched_priority = %d\n",sc.sched_priority );
sc.sched_priority = 99;
sc1.sched_priority = 1;
//设置静态优先级
pthread_attr_setschedparam(&attr, &sc);
pthread_attr_setschedparam(&attr1, &sc1);
pthread_create(&pid, &attr, func, NULL);
pthread_create(&pid1, &attr1, func1, NULL);
pthread_join(pid, NULL);
pthread_join(pid1, NULL);
return 0;
}
6.获取、设置动态优先级nice
功能
获取、设置线程动态优先级
头文件
#include <unistd.h>
原型
int nice(int inc);
参数
inc 动态优先级: -20到19
返回值
成功 新的动态优先级 失败 -1
备注
1,动态优先级数值越大,优先级越低
2,如果编译器gcc的版本低于2.2.4 (不含),该函数成功将返回0
7.获取、设置栈大小和警戒区大小
功能
获取、设置线程栈大小、警戒区大小
头文件
#include <pthread.h>
原型
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize);
参数
attr 线程属性变量
stacksize 线程栈的大小
guardsize 警戒区的大小
返回值
成功 0 失败 errno
线程栈是非常重要的资源,用以存放诸如函数形参、局部变量、线程切换现场寄存器数据等等,一个多线程进程的栈空间,包含了所有线程各自的栈
如果发现一条线程的栈有可能会溢出,那么也许需要使用该函数来增大栈空间,但事实上常常不需要这么做,而警戒区指的是没有任何访问权限的内存,用来保护相邻的两条线程的栈空间不被彼此践踏。线程跟进程类似,在缺省的状态下退出之后,会变成僵尸线程,并且保留退出值。其他线程可以通过相关 API 接合该线程——使其资源被系统回收,如果愿意的话还可以顺便获取其退出值。
test
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <time.h>
#include <pthread.h>
void *func(void *arg)
{
int k = 0;
while(1)
{
printf("k = %d\n", k);
sleep(1);
k++;
if (k == 3)
{
break;
}
}
}
int main(int argc, char const *argv[])
{
pthread_t pid;
//设置线程的分离属性
pthread_attr_t attr;
//初始化线程的分离属性
pthread_attr_init(&attr);
//获取栈大小和警戒区大小
unsigned long int stack;
unsigned long int guard;
// pthread_attr_setstacksize(&attr, 4000000);
// pthread_attr_setguardsize(&attr, 1024);
pthread_attr_getstacksize(&attr, &stack);
pthread_attr_getguardsize(&attr, &guard);
printf("栈大小:%lud\n", stack);
printf("警戒区大小:%lud\n", guard);
int oldstat;
int oldtype;
// pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstat);//关闭取消请求
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstat);//使能取消请求
if (oldstat == PTHREAD_CANCEL_ENABLE)
{
printf("使能取消请求\n");
}
if (oldstat == PTHREAD_CANCEL_DISABLE)
{
printf("关闭取消请求\n");
}
// pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);//立即响应
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);//延时响应
if (oldtype == PTHREAD_CANCEL_DEFERRED)
{
printf("延时响应\n");
}
if (oldtype == PTHREAD_CANCEL_ASYNCHRONOUS)
{
printf("立即响应\n");
}
pthread_create(&pid, &attr, func, NULL);
pthread_join(pid, NULL);
return 0;
}
8.退出线程pthread_exit\接合指定线程pthread_join\pthread_tryjoin_np
功能
退出线程
头文件
#include <pthread.h>
原型
void pthread_exit(void *retval);
参数
retval 线程退出值
返回值
不返回
功能
接合指定线程
头文件
#include <pthread.h>
原型
int pthread_join(pthread_ t thread, void **retval);
int pthread_tryjoin_np( pthread_ _t thread, void **retval);
参数
thread 线程TID
retval 储存线程退出值的内存的指针
返回值
成功 0 失败 errno
注意:
1,如果线程退出时没有退出值,那么 retval 可以指定为 NULL。
2,pthread_join( )指定的线程如果尚在运行,那么他将会阻塞等待。
3,pthread_tryjoin_np( )指定的线程如果尚在运行,那么他将会立即出错返回。
9.线程取消pthread_cancel
功能
给指定线程发送-一个取消请求
头文件
#include <pthread.h>
原型
int pthread_cancel(pthread_ _t thread);
参数
thread 线程TID
返回值
成功 0 失败 errno
在某个时刻不能等某个线程“自然死亡”,而需要勒令其马上结束,此时可
以给线程发送一个取消请求,让其中断执行而退出.
当线程收到一个取消请求时,他将会如何表现取决于两个东西:
一是当前的取消状态,
二是当前的取消类型。
线程的取消状态很简单分别是:
PTHREAD_CANCEL_ENABLE 和PTHREAD_CANCEL_DISABLE
前者是缺省的,代表线程可以接受取消请求,后者代表关闭取消请求,不对其响应。而在线程接受取消请求的情况下,如何停下来又取决于两种不同的响应取消请求的策略——延时响应和立即响应,当采取延时策略时,线程并不会立即退出,而是要遇到所谓的“取消点”之后,才退出。而“取消点”,指的是一系列指定的函数.
test
#define _GNU_SOURCE
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <time.h>
#include <pthread.h>
int a;
//线程任务函数
void *func(void *arg)
{
int k = 0;
while(1)
{
printf("k = %d\n", k);
sleep(1);
k++;
if (k == 3)
{
break;
}
}
printf("线程结束\n");
char *p = "123";
int *a = malloc(4);
*a = 456;
pthread_exit((void *)a);
}
int main(int argc, char const *argv[])
{
pthread_t pid;
pthread_create(&pid, NULL, func, NULL);
// int i = 0;
// while(1)
// {
// printf("i = %d\n", i);
// sleep(1);
// i++;
// if (i == 10)
// {
// break;
// }
// }
//等待线程结束
// pthread_tryjoin_np(pid, NULL);
pthread_cancel(pid);
// void *p1 = malloc(4);
// pthread_join(pid, &p1);
// printf("p1 = %d\n", *(int *)p1);
printf("主进程结束\n");
return 0;
}
10.设置和获取线程的取消状态和取消类型pthread_setcancelstate\pthread_setcanceltype
功能
获取、设置线程的取消状态和取消类型
头文件
#include <pthread.h>
原型
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);
参数
state 新的取消状态
PTHREAD_CANCEL_ENABLE: 使能取消请求
PTHREAD_CANCEL_DISABLE: 关闭取消请求
oldstate 旧的取消状态
type 新的取消类型
PTHREAD_CANCEL_DEFERRED:延时响应
PTHREAD_CANCEL_ASYNCHRONOUS:立即响应
oldtype 旧的取消类型
返回值
成功 0 失败 errno
备注
1,缺省的取消状态是PTHREAD_CANCEL_ENABLE
2,缺省的取消类型是PTHREAD_CANCEL_DEFERRED
11.压栈、或弹栈线程的取消处理例程pthread_cleanup_push\pthread_cleanup_pop
由于线程任何时刻都有可能持有诸如互斥锁、信号量等资源,一旦被取消很有可能导致别的线程出现死锁,因此如果一条线程的确可能被取消,那么在被取消之前必须使用以下API 来为将来可能出现的取消请求注册“处理例程”,让这些例程自动释放持有的资源.
功能
压栈、或弹栈线程的取消处理例程
头文件
#include <pthread.h>
原型
void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);
参数
routine 线程的取消处理例程
arg 线程的取消处理例程的参数
execute
0 弹栈线程的取消处理例程,但不执行该例程
非0 弹栈线程的取消处理例程,并执行该例程
返回值
不返回
备注
1,使用pthread_cleanup_push()可以为线程的取消请求压入多个处理例程,这些
例程会以栈的形式保留起来,在线程被取消之后,他们以弹栈的形式后进先出地 依次被执行。
2,这两个函数必须配套使用,而且必须出现在同一层代码块中。
HREAD_CANCEL_DISABLE: 关闭取消请求
oldstate 旧的取消状态
type 新的取消类型
PTHREAD_CANCEL_DEFERRED:延时响应
PTHREAD_CANCEL_ASYNCHRONOUS:立即响应
oldtype 旧的取消类型
返回值
成功 0 失败 errno
备注
1,缺省的取消状态是PTHREAD_CANCEL_ENABLE
2,缺省的取消类型是PTHREAD_CANCEL_DEFERRED
11.压栈、或弹栈线程的取消处理例程pthread_cleanup_push\pthread_cleanup_pop
由于线程任何时刻都有可能持有诸如互斥锁、信号量等资源,一旦被取消很有可能导致别的线程出现死锁,因此如果一条线程的确可能被取消,那么在被取消之前必须使用以下API 来为将来可能出现的取消请求注册“处理例程”,让这些例程自动释放持有的资源.
```c
功能
压栈、或弹栈线程的取消处理例程
头文件
#include <pthread.h>
原型
void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);
参数
routine 线程的取消处理例程
arg 线程的取消处理例程的参数
execute
0 弹栈线程的取消处理例程,但不执行该例程
非0 弹栈线程的取消处理例程,并执行该例程
返回值
不返回
备注
1,使用pthread_cleanup_push()可以为线程的取消请求压入多个处理例程,这些
例程会以栈的形式保留起来,在线程被取消之后,他们以弹栈的形式后进先出地 依次被执行。
2,这两个函数必须配套使用,而且必须出现在同一层代码块中。