Linux系统线程POSIX

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 静态优先级: 099

返回值 
	成功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 动态优先级: -2019
返回值
	成功 新的动态优先级	 失败 -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,这两个函数必须配套使用,而且必须出现在同一层代码块中。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yengi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值