百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 优雅编程 > 正文

Linux系统多线程应用API详解(二)---线程的属性设置/获取

sinye56 2024-11-06 12:02 3 浏览 0 评论

---.初始化线程属性:

int pthread_attr_init(pthread_attr_t*), int pthread_attr_destory(pthread_attr_t*),

1)说明:功能是初始化和除初始化一个线程属性对象;

2)参数:

线程具有属性,用pthread_attr_t 结构体表示。

	typedef struct
	{
	        int                       detachstate;   // 线程的分离状态
		int                       schedpolicy;   // 线程调度策略
		structsched_param         schedparam;    // 线程的调度参数
		int                       inheritsched;  // 线程的继承性
		int                       scope;         // 线程的作用域
		size_t                    guardsize;     // 线程栈末尾的警戒缓冲区大小
		int                       stackaddr_set; // 线程的栈设置
		void*                     stackaddr;     // 线程栈的位置
		size_t                    stacksize;     // 线程栈的大小
	} pthread_attr_t;
			

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

3)例子:(一般会配合属性的set和get函数一起使用)

	#include <stdio.h>
	#include <string.h>
	#include <pthread.h>
	#include <sched.h>
	void *child_thread(void *arg)
	{
		int policy = 0;
		int max_priority = 0,min_priority = 0;
		struct sched_param param;
		pthread_attr_t attr;    //线程属性结构体
			 
		/*初始化线程属性*/
		pthread_attr_init(&attr);
				
		/*修改线程的继承性属性*/
		pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
				
		/*获取线程的继承性属性*/
		pthread_attr_getinheritsched(&attr, &policy);
		if(policy == PTHREAD_EXPLICIT_SCHED){
			printf("Inheritsched:PTHREAD_EXPLICIT_SCHED\n");
		}
		if(policy == PTHREAD_INHERIT_SCHED){
			printf("Inheritsched:PTHREAD_INHERIT_SCHED\n");
		}
			 
		/*修改线程的调度方式属性*/
		pthread_attr_setschedpolicy(&attr, SCHED_RR);
				
		/*获取线程的调度方式属性*/
		pthread_attr_getschedpolicy(&attr, &policy);
		if(policy == SCHED_FIFO){
			printf("Schedpolicy:SCHED_FIFO\n");
		}
		if(policy == SCHED_RR){
			printf("Schedpolicy:SCHED_RR\n");
		}
		if(policy == SCHED_OTHER){
			printf("Schedpolicy:SCHED_OTHER\n");
		}
				
		/*获取线程的最高优先级属性*/
		max_priority = sched_get_priority_max(policy);
				
		/*获取线程的最低优先级属性*/
		min_priority = sched_get_priority_min(policy);
		printf("Maxpriority:%u, Minpriority:%u\n",max_priority, min_priority);
					 
		param.sched_priority = max_priority;
		pthread_attr_setschedparam(&attr, param);
		printf("sched_priority:%u\n",param.sched_priority);
				
		/*去初始化线程属性*/
		pthread_attr_destroy(&attr);
	}
			 
	int main(int argc,char *argv[ ])
	{
		pthread_t child_thread_id;
		pthread_create(&child_thread_id, NULL, child_thread, NULL);
		pthread_join(child_thread_id, NULL);
			 
		return 0;
	}

---.设置线程detach属性:

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);

1)说明:

a. 在线程的所有属性中, 最重要的是分离属性(detach status);

b. 一个线程可以是等待线程(joinable_thread)或者分离线程(detach thread), 默认是joinable thread;

c. 对于一个非分离(joinable)线程joinbale_thread在退出后,资源不会被立刻释放,直到被thread_join获取它的返回值;

d. 对于一个分离(detach)线程在退出之后, 资源会被立刻释放, 其他线程无法获悉其返回值;

2)参数:

--attr: 结构中的detachstate线程属性,让线程以分离状态启动;

--detachstate: 可选为PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE_JOINABLE(非分离线程);

3)例子:

	/* 1. 创建线程的属性变量 */
	pthread_attr_t attr;   
	/* 2. 初始化此属性变量*/		
	phtread_attr_init(&attr);  
			
	/* 3. 修改线程为可分离的属性*/
	 int detachstate = PTHREAD_CREATE_DETACHED;
	pthread_setdetachstatus(&attr, detachstate); 
			
	 /* 4. 获取分离状态属性  */
	pthread_attr_getdetachstate(&attr, &detachstate);
	if(detachstate == PTHREAD_CREATE_DETACHED){
		printf("datachstate: PTHREAD_CREATE_DETACHED\n");
	}
			
	/* 5. 创建一个线程 */
	pthread_create(&t,&attr,&function,NULL); 
			
	/* 6. 创建完后,即可销毁此属性变量*/
	pthread_destory(&attr); 
			
	/* 7. 注意!分离的线程无法被join*/
	// pthread_join(t, NULL); 
			
	return; 		

---.获取线程detach属性:

int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);

1)说明:用于获取线程属性对象的分离状态(detach state),即获取线程是以可分离状态(detached)还是以连接状态(joinable)运行的

2)参数:

--attr:获取到的线程属性填充到attr结构体中;

--detachstate:将attr中的线程属性对象的分离状态属性返回到由 detachstate 指向的指针变量中;

3)例子:(见上面pthread_attr_setdetachstate例子)


---.设置线程被取消属性:

int pthread_setcancelstate(int state, int *oldstate)

1)说明:使用场景是在使用pthread_cancel函数时,要先设置此线程的可取消性;

2)参数:

--state: 开关;PTHREAD_CANCEL_DISABLE--关闭;PTHREAD_CALCEL_ENABLE--打开;

--oldState: 第二个参数传入一个 int 类型的指针,然后会将旧的状态存储到这个值当中;

3)例子(让线程取消无效):

	#include <stdio.h>
	#include <pthread.h>
	#include <unistd.h>
	void* func(void* arg)
	{
		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
		while(1)
		{
			sleep(1);
		}
		return NULL;
	}
			
	int main() 
	{
		pthread_t t;
		pthread_create(&t, NULL, func, NULL);
		pthread_cancel(t);
		void* res;
		pthread_join(t, &res);
		if(res == PTHREAD_CANCELED)
		{
			printf("thread was canceled\n");
		}
		return 0;
	}

---设定线程取消的方式

int pthread_setcanceltype (int __type, int * oldtype);

1)说明: 设置线程响应Cancel信号的方式

2)参数:

--type:有两个可选值,分别是:

PTHREAD_CANCEL_DEFERRED(默认值):同步取消;

PTHREAD_CANCEL_ASYNCHRONOUS:异步取消

PTHREAD_CANCEL_DISABLE : 不能取消

--oldtype:用于接收线程先前所遵循的 type 值,如果不需要接收该值,置为 NULL 即可。

3)例子:

void* threadFunction(void* arg) 
{
	// 设置取消状态为允许取消
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

	// 设置取消类型为异步取消
	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
	printf("Thread started\n");

	while (1) {
		printf("Thread is running\n");
		sleep(1);
	}

	printf("Thread finished\n");
	return NULL;
}

int main() {
	pthread_t thread;
	pthread_create(&thread, NULL, threadFunction, NULL);

	// 主线程休眠5秒后取消子线程
	sleep(5);
	pthread_cancel(thread);

	// 等待子线程结束
	pthread_join(thread, NULL);
	printf("Main thread finished\n");

	return 0;
}

---.设置/获取线程栈末尾的警戒缓冲区大小:

int pthread_attr_setguardsize (pthread_attr_t *__attr, size_t __guardsize);

int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize);

1)说明:

设置栈溢出保护区的大小,什么是栈溢出保护区?由于线程的堆栈是有大小限制的,所有就会出现堆栈用满的情况。 线程的堆栈如果用满可能导致对内核空间的破坏,会使系统崩溃。 因此Linux为线程设置了一个满栈警戒区。

2)参数:

--__attr: 设置线程的属性填充到attr结构体中;

--__guardsize:以字节为单位,设置和获取栈溢出保护区的大小。

--返回值: 0---成功;1---失败;

3)例子:

	/* 1. 创建线程的属性变量 */
	pthread_attr_t attr;   
	/* 2. 初始化此属性变量*/		
	phtread_attr_init(&attr);  			
	/* 3. 修改线程为可分离的属性*/
	 int __guardsize = 2048;
	pthread_attr_setguardsize(&attr, __guardsize); 			
	/* 4. 获取分离状态属性  */
	pthread_attr_getguardsize(&attr, &__guardsize);
	/* 5. 创建一个线程 */
	pthread_create(&t,&attr,&function,NULL); 
	/* 6. 创建完后,即可销毁此属性变量*/
	pthread_destory(&attr); 		

---.设置/获取线程的优先级:

int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);

int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);

1)说明:

a. 可以通过以下两个函数来获得线程可以设置的最高和最低优先级,函数中的策略即上述三种策略的宏定义:

   int sched_get_priority_max(int policy);
   int sched_get_priority_min(int policy);

  b. SCHED_OTHER是不支持优先级使用的,而SCHED_FIFO和SCHED_RR支持优先级的使用,他们分别为1和99,数值越大优先级越高。

c. 优先级设置的数据结构体定义如下:

      struct sched_param
      {
	   int __sched_priority;
      };	 

2)参数:

--attr:用来填充线程属性的结构体;

--param:线程属性中设置优先级的结构体变量;

--返回值: 0---成功;1---失败

3)例子:

struct sched_param sparam;
int prio_min;
int prio_max;
int prio_mid;
 int status;
  
/* 1. 创建线程的属性变量 */
pthread_attr_t attr;   

/* 2. 初始化此属性变量*/		
phtread_attr_init(&attr);  
			
/* 3.设置线程的优先级*/
 prio_min = sched_get_priority_min(SCHED_FIFO);
 prio_max = sched_get_priority_max(SCHED_FIFO);
 prio_mid = (prio_min + prio_max) / 2;

 sparam.sched_priority = prio_mid;
 status = pthread_attr_setschedparam(&attr,&sparam); 
			   
 /*4.获取线程的优先级*/  
 status = pthread_attr_getschedparam(&attr, &sparam); 		

/* 5. 创建一个线程 */
pthread_create(&t,&attr,&function,NULL); 
			
/* 6. 创建完后,即可销毁此属性变量*/
pthread_destory(&attr); 		

---.设置/获取线程的调度策略:

int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);

int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);

1)说明:

线程的调度策略,主要包括SCHED_OTHER(正常、非实时),SCHED_RR(实时、轮转发)和SCHED_FIFO(实时、先入先出)三种, 缺省为SCHED_OTHER,后两种策略仅对超级用户有效;

a. 实时线程:单位时间响应能力强,拥有1-99个静态优先级,数字越大,优先级越高。需要有管理员权限才能启动实时线程。

---特点:

(1) 实时线程分99各静态优先级,数字越大,优先级越高。

(2) 高优先级的实时线程会完全抢占低优先级实时线程的资源。

(3) 在实时线程中支持抢占调度策略跟轮训调度策略

(4) 必须拥有超级用户权限才能够运行

b. 非实时线程:单位时间中,并没有过分的去在乎响应能力的一个线程,里只有一个静态优先级9,也就是非实时线程中,它是没有静态优先级的概念,它所有执行过程都是系统自动分配的。

---特点:

(1) 非实时线程只有一个静态优先级,所以非实时线程的任务无法抢占他人的资源;

(2) 在非实时线程当中只支持其他调度策略(自动适配的,系统分配的调度策略);

(3) 不拥有抢占所有运行资源的能力

(4) 支持动态优先级系统自适应,从-20 到 19的动态优先级;

c.调度策略

(1)抢占式调度策略:在同一优先级的情况下,抢占调度策略的线程一旦运行到便会一直抢占CPU资源, 而同一优先级的只能一直抢占式调度策略的线程退出才能被运行到;

(2)轮训式调度策略:在同一静态优先级的情况下,大家一起合力共享时间片,不会一直抢占CPU资源;

(3)其他普通式调度策略:只能对非实时线程,由系统自动分配时间片,并且根据运行状态自动分配动态优先级。

2)参数:

--attr:用来填充线程属性的结构体变更;

--policy:调度策略,可以是SCHED_FIFO、SCHED_RR或SCHED_OTHER。

--返回值: 0---成功;1---失败;

3)例子(关于调度策略/调度参数/继承性的例子统一如下):

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sched.h>
void *thread_func(void *arg) {
	printf("I'm a new thread.\n");
	pthread_exit(NULL);
}
int main() {
	int policy;
	struct sched_param param;
				
	/* 1. 初始化线程属性 */
	pthread_attr_t attr;
	pthread_attr_init(&attr);
				
	/*2. 设置继承调度策略 */
	pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
				
	/*3. 设置线程调度策略为SCHED_FIFO */
	pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
				
	/* 4. 设置线程调度参数  */
	param.sched_priority = 80;
	pthread_attr_setschedparam(&attr, ?m);
				
	/* 5.创建新线程并运行 */
	pthread_t new_thread;
	if (pthread_create(&new_thread, &attr, thread_func, NULL) != 0) {
		perror("pthread_create error");
		return 1;
	}
	/*6. 获取线程调度策略和参数 */
	pthread_attr_getschedpolicy(&attr, &policy);
	pthread_attr_getschedparam(&attr, ?m);

	/* 7输出线程调度策略和参数 */				
	printf("Thread policy: ");
	switch (policy) {
		case SCHED_FIFO:
			printf("FIFO\n");
			break;
		case SCHED_RR:
			printf("RR\n");
			break;
		case SCHED_OTHER:
			printf("OTHER\n");
			break;
		default:
			printf("UNKNOWN\n");
	}
	printf("Thread priority: %d\n", param.sched_priority);
	/* 8. 等待子线程结束  */
	if (pthread_join(new_thread, NULL) != 0) {
		perror("pthread_join error");
		return 1;
	}
	return 0;
}				 

---.设置/获取线程调度的参数:

int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);

int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);

1)说明:该函数用于设置/获取线程的调度参数,即线程的优先级。优先级越高的线程获取CPU时间的机会越大。

2)参数:

--pthread_attr_t *attr:待设置的线程属性对象;

--const struct sched_param *param:线程的调度参数,包括优先级和调度策略

3)例子:(见上面调度策略例子)


---.设置/获取线程是否继承父栈调度策略:

int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);

int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched);

1)说明:设置/获取线程是否继承父栈调度策略;

2)参数:

--pthread_attr_t *attr:待设置的线程属性对象;

--__inherit:可设置为两种情况, PTHREAD_EXPLICIT_SCHED---不继承,PTHREAD_INHERIT_SCHED---继承;

3)例子:(见上面调度策略例子)


---.设置/获取线程绑定属性

int pthread_attr_setscope(pthread_attr_t *attr, int scope);

int pthread_attr_getscope(const pthread_attr_t *attr, int *scope);

1)说明:

a. 轻进程和Linux系统的内核线程拥有相同的概念,属于内核的调度实体。一个轻进程可以控制一个或多个线程。

b. 被绑定的线程具有较高的响应速度,因为操作系统的调度主体是轻进程,绑定线程可以保证在需要的时候它总有一个轻进程可用。绑定属性作用就是如此。

2)参数:

---attr:线程属性对象的指针;

---scope:绑定类型,拥有两个取值:PTHREAD_SCOPE_SYSTEM---绑定的; PTHREAD_SCOPE_PROCESS---非绑定的

3)例子(设置线程绑定属性):

#include <stdio.h>  
#include <pthread.h>  
……  
int main( int argc, char *argv[] )  
{  
	pthread_attr_t attr;  
	pthread_t th;  
	……  
	pthread_attr_init( &attr );  
	pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM );  
	pthread_create( &th, &attr, thread, NULL );  
	……  
}  

---.设置/获取线程堆栈的起始地址:

int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr);

int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr);

1)说明:用于自定义线程的栈起始地址;

2)参数:

--attr:指向一个线程属性的指针

--stackaddr:自定义线程的堆栈起始地址

--返回值: 成功--0;失败:错误号

3)例子:

#include <stdio.h>  
#include <pthread.h>  
		
#define SIZE 0x100000
		
void *th_fun(void *arg)
{
	while (1)
	{
		sleep(1);
	}
}
		
int main( int argc, char *argv[] )  
{  
	pthread_attr_t attr;  
	pthread_t th;  
	void *stackaddr = NULL;
	pthread_attr_init( &attr); 	
			
	/*自定义栈地址空间*/
	stackaddr = malloc(SIZE);
	pthread_attr_setstackaddr (&attr, stackaddr);
	pthread_attr_setstacksize (&attr, SIZE);	
			
	pthread_create( &th, &attr, th_fun, NULL );  
	……  
}  
		

---.设置/获取线程堆栈的大小:

int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);

int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);

1)说明: 当系统中有很多线程时,可能需要减小或增加每个线程栈的默认大小,防止进程的地址空间不够用或过多浪费;此函数可以设置线程栈空间的大小 ;

2)参数:

--attr:指向一个线程属性的指针

--stacksize:线程的堆栈大小

--返回值: 成功--0;失败:错误号

3)例子:(见上面例子)

---.设置/获取线程栈的地址和大小:

int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);

int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize);

1)说明:设置线程栈的地址和大小,设定的栈地址必须以linux页面大小对齐,可以使用posix_memalign()分配页面对齐的内存。栈的大小默认通常为8MB。最小栈大小为16KB。

2)参数:

--attr:指向一个线程属性的指针

--stackaddr:设置线程的栈地址;

--stacksize:设置线程的栈大小

--返回值: 成功--0;失败:错误号

3)例子:

#define SIZE 0x100000		
void *th_fun(void *arg)
{
	while (1)
	{
		sleep(1);
	}
}
		
int main()
{
	pthread_t tid;
	int err, detachstate, i = 1;
		
	pthread_attr_t attr;
	size_t stacksize;
	void *stackaddr;
		
	pthread_attr_init(&attr);  			//线程属性初始化
	pthread_attr_getstack(&attr, &stackaddr, &stacksize); //获取线程的栈地址
		
	while (1) 
	{
		stackaddr = malloc(SIZE);
		if (stackaddr == NULL) 
		{
			perror("malloc");
			exit(1);
		}
		
		stacksize = SIZE;
		pthread_attr_setstack(&attr, stackaddr, stacksize); //设置线程的栈地址
		err = pthread_create(&tid, &attr, th_fun, NULL); //创建线程
		if (err != 0) 
		{
			printf("%s\n", strerror(err));
			exit(1);
		}
		printf("%d\n", i++);
	}
		
	pthread_attr_destroy(&attr); //销毁线程属性所占用的资源函数
		
	return 0;
}	

---.设置/获取线程CPU亲和力函数:

int pthread_attr_setaffinity_np(pthread_attr_t *attr, size_t cpusetsize, const cpu_set_t *cpuset);

int pthread_attr_getaffinity_np(const pthread_attr_t *attr, size_t cpusetsize, cpu_set_t *cpuset);

1)说明:用于设置线程的 CPU 亲和性(CPU Affinity)。它允许将线程绑定到特定的 CPU 核心或 CPU 集合上,以控制线程在哪些 CPU 上运行。 另外,也可以使用另外一组函数来设置和获取CPU亲和力:

int pthread_setaffinity_np (pthread_t thread, size_t __cpusetsize, const cpu_set_t *__cpuset);

int pthread_getaffinity_np (pthread_t thread, size_t __cpusetsize, cpu_set_t *__cpuset);

区别:前一组函数是在创建thread前的属性设置中进行的;后者是在创建thread之后设置的;

一般推荐使用前面一组函数;

2)参数:

--attr:待设置的线程属性对象;

--thread:要设置 CPU 亲和性的线程标识符。

--cpusetsize:CPU 亲和性集合的大小(以字节为单位)。

--cpuset:指向 CPU 亲和性集合的指针,其中包含要绑定线程的 CPU。

--返回值:成功返回 0,失败返回错误代码。

3)例子:

-----------------用法1:pthread_attr_setaffinity_np -----------------------------

	#define _GNU_SOURCE
	#include <stdio.h>
	#include <pthread.h>
	#include <unistd.h>
	#include <sched.h>

	void *thread_func(void *arg)
	{
		usleep(10000);

		/* 获取当前线程的 CPU 亲和性 */
		cpu_set_t cpuset;
		CPU_ZERO(&cpuset);
		pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
		// 打印当前线程绑定的 CPU
		for (int i = 0; i < CPU_SETSIZE; i++) {
			if (CPU_ISSET(i, &cpuset)) {
				printf("thread is running on cpu %d\n", i);
			}
		}
		return NULL;
	}

	int main() {
		pthread_t tid;
		pthread_attr_t attr;
		pthread_attr_init(&attr);

		/* 创建线程并设置其只能在 cpu1 上运行 */
		cpu_set_t mask;
		CPU_ZERO(&mask);
		CPU_SET(1, &mask);
		pthread_attr_setaffinity_np(&attr, sizeof(mask), &mask);
		pthread_create(&tid, &attr, thread_func, NULL);

		pthread_attr_destroy(&attr);
		pthread_join(tid, NULL);
		return 0;
	}		

-------------------------用法2:pthread_setaffinity_np------------------------------

#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sched.h>

void *thread_func(void *arg)
{
	usleep(10000);

	/* 获取当前线程的 CPU 亲和性  */
	cpu_set_t cpuset;
	CPU_ZERO(&cpuset);
	pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
	// 打印当前线程绑定的 CPU
	for (int i = 0; i < CPU_SETSIZE; i++) {
		if (CPU_ISSET(i, &cpuset)) {
			printf("thread is running on cpu %d\n", i);
		}
	}
	return NULL;
}

int main() {
	// 创建线程并设置其只能在 cpu0 1 2 上运行
	pthread_t tid;
	cpu_set_t mask;
	CPU_ZERO(&mask);
	CPU_SET(0, &mask);
	CPU_SET(1, &mask);
	CPU_SET(2, &mask);
	pthread_create(&tid, NULL, thread_func, NULL);
			
	/*thread create 之后进行设置*/
        pthread_setaffinity_np(tid, sizeof(mask), &mask);

	pthread_join(tid, NULL);
	return 0;
}			

---.设置/获取默认的线程属性:

int pthread_getattr_default_np(pthread_attr_t *attr);

int pthread_setattr_default_np(pthread_attr_t *attr);

1)说明:设置/获取线程的默认属性

2)参数:

---attr:待设置的线程属性对象;

3)例子:

 #define _GNU_SOURCE
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
  #include <errno.h>

 #define errExitEN(en, msg) \
	 do { errno = en; perror(msg); \
	 exit(EXIT_FAILURE); } while (0)

static void display_pthread_attr(pthread_attr_t *attr)
{
	int s;
        size_t stacksize;
	size_t guardsize;
	int policy;
	struct sched_param schedparam;
        int detachstate;
	int inheritsched;

	s = pthread_attr_getstacksize(attr, &stacksize);
	if (s != 0)
		 errExitEN(s, "pthread_attr_getstacksize");
	printf("Stack size:   %zd\n", stacksize);

        s = pthread_attr_getguardsize(attr, &guardsize);
	 if (s != 0)
		 errExitEN(s, "pthread_attr_getguardsize");
	printf("Guard size:          %zd\n", guardsize);

	s = pthread_attr_getschedpolicy(attr, &policy);
	if (s != 0)
	        errExitEN(s, "pthread_attr_getschedpolicy");
	printf("Scheduling policy:   %s\n",
		(policy == SCHED_FIFO) ? "SCHED_FIFO" :
		(policy == SCHED_RR) ? "SCHED_RR" :
		(policy == SCHED_OTHER) ? "SCHED_OTHER" : "[unknown]");

	s = pthread_attr_getschedparam(attr, &schedparam);
	 if (s != 0)
		errExitEN(s, "pthread_attr_getschedparam");
	printf("Scheduling priority: %d\n", schedparam.sched_priority);

	s = pthread_attr_getdetachstate(attr, &detachstate);
	if (s != 0)
		 errExitEN(s, "pthread_attr_getdetachstate");
	 printf("Detach state:        %s\n",
		(detachstate == PTHREAD_CREATE_DETACHED) ? "DETACHED" :
		(detachstate == PTHREAD_CREATE_JOINABLE) ? "JOINABLE" :
		 "???");

	 s = pthread_attr_getinheritsched(attr, &inheritsched);
	 if (s != 0)
		errExitEN(s, "pthread_attr_getinheritsched");
	 printf("Inherit scheduler:   %s\n",
		(inheritsched == PTHREAD_INHERIT_SCHED) ? "INHERIT" :
		(inheritsched == PTHREAD_EXPLICIT_SCHED) ? "EXPLICIT" :
		 "???");
 }
				   
void *thread_func(void *arg)
{
     while (1)
    {
	sleep(1);
     }
}

int  main(int argc, char *argv[])
{
	 int s;
	 pthread_attr_t attr;
	 pthread_attr_t attr2;
					
	/* 1.-----获取线程默认的属性*/
	s = pthread_getattr_default_np(&attr);
	if (s != 0)
		errExitEN(s, "pthread_getattr_default_np");

	/* 2.-----打印线程默认的属性*/
	display_pthread_attr(&attr);
					   
        /* 3.-----设置线程默认的属性*/ 
	s = pthread_setattr_default_np(&attr);					   
					   
	/*4. 创建一个线的线程*/
	pthread_create(&tid, &attr, thread_func, NULL);
					   
        exit(EXIT_SUCCESS);
}

---.获取某个正在运行的线程属性:

int pthread_getattr_np (pthread_t threadId, pthread_attr_t *__attr)

1)说明: 获得该线程使用的线程属性。

2)参数:

---threadId: 指定ID的线程;

---attr:待设置的线程属性对象;

3)例子:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

static void *thread_start(void *arg)
{
     printf("Attributes of created thread:\n");
     pthread_attr_t attr;
		   
     /*获取当前运行线程的属性*/
     int s = pthread_getattr_np((pthread_self(), &attr);
		   
     size_t stack_size, guard_size;
     void *stack_addr;

    /*打印栈空间的警戒线大小*/
     s = pthread_attr_getguardsize(attr, &guard_size);
     if (s != 0)
           handle_error_en(s, "pthread_attr_getguardsize");
     printf("%sGuard size  = %d bytes\n", prefix, guard_size);

    /*打印栈空间的大小和基地址*/
     s = pthread_attr_getstack(attr, &stack_addr, &stack_size);
     if (s != 0)
           handle_error_en(s, "pthread_attr_getstack");
     printf("%sStack address       = %p", prefix, stack_addr);
     if (stack_size > 0)
          printf(" (EOS = %p)", (char *) stack_addr + stack_size);
     printf("\n");
     printf("%sStack size          = 0x%x (%d) bytes\n",
           prefix, stack_size, stack_size);				   
		   
      s = pthread_attr_destroy(&attr);
      if (s != 0)
               handle_error_en(s, "pthread_attr_destroy");
       exit(EXIT_SUCCESS);         /* Terminate all threads */
 }

 int   main(int argc, char *argv[])
 {
       int s;
       pthread_t thr;
       pthread_attr_t &attr;

       pthread_attr_init(&attr);	
       s = pthread_create(&thr, &attr, &thread_start, NULL);
       if (s != 0)
           handle_error_en(s, "pthread_create");
	
      s = pthread_attr_destroy(&attr);
       pause();    /* Terminates when other thread calls exit() */
  } 

---设置/获取线程名称

int pthread_setname_np(pthread_t thread, const char *name);

int pthread_getname_np(pthread_t thread, char *name, size_t len);

1)说明:动态设置当前线程的名称

2)参数:

---thread:当前正在运行的线程ID;

---name: 设置的线程名称;

3)例子:

static void *threadfunc(void *parm)
 {
	 sleep(5);          // allow main program to set the thread name
	 return NULL;
}

 int main(int argc, char **argv)
{
	pthread_t thread;
        int rc;
	char thread_name[NAMELEN];

	 /*1. ----创建一个线程*/
	rc = pthread_create(&thread, NULL, threadfunc, NULL);
	if (rc != 0)
		 errExitEN(rc, "pthread_create");

	 /*2. ----获取此线程的默认名称 */
	rc = pthread_getname_np(thread, thread_name, NAMELEN);
	if (rc != 0)
		 errExitEN(rc, "pthread_getname_np");

	printf("Created a thread. Default name is: %s\n", thread_name);
			   
        /*2. ----设置此线程的名称 */
	 rc = pthread_setname_np(thread,  "THREADTEST");
	if (rc != 0)
		errExitEN(rc, "pthread_setname_np");

	sleep(2);

	rc = pthread_getname_np(thread, thread_name,
		(argc > 2) ? atoi(argv[1]) : NAMELEN);
	if (rc != 0)
	       errExitEN(rc, "pthread_getname_np");
	printf("The thread name after setting it is %s.\n", thread_name);

	rc = pthread_join(thread, NULL);
	if (rc != 0)
		errExitEN(rc, "pthread_join");

		printf("Done\n");
		exit(EXIT_SUCCESS);
 	 }

---设置/获取线程并发度

int pthread_setconcurrency(int new_level);

int pthread_getconcurrency(void);

1)说明:用来控制用户级线程可以映射到内核线程或进程的数目。

a. 并发级别仅在N:M线程模型中有效,设置并发级别,给内核一个提示:表示提供给定级别数量的核心线程来映射用户线程是高效的(仅仅是一个提示),默认为0, 内核按照默认的方式进行并发;

b. 如果操作系统的实现在内核级的线程和用户级的线程之间保持一对一的映射,改变并发度并不会有什么效果,因为所有的用户级线程都可能被调度到。但如果操作系统的实现让用户级线程到内核级线程或进程之间的映射关系是多对一的话,那么在给定时间内增加可运行的用户级线程数,可能会改善性能。

c. 在某些系统中,如果你不调用pthread_setconcurrency()函数,那么系统中的运行的线程仅仅是第一个被创建的线程,其他线程根本不会被运行。

d. 为了增强unix或者是linux系统的移植性,请在合适的地方调用此函数,清晰的告诉系统我们使用的线程个数。

2)参数:

--new_level:并发度的级别,一般为线程个数;

--返回值:如果以前未调用 pthread_setconcurrency() 函数,则 pthread_getconcurrency() 将返回零。

3)例子:

	pthread_t pid1, pid2;
			 
	......
        pthread_setconcurrency(2); 
	pthread_create(&pid1, NULL, thread_func1, &arg);
	pthread_create(&pid2, NULL, thread_func2, &arg);					
	......			
 

---强制放弃使用的处理器的调度

int pthread_yield (void);

1)说明: 作用是通知调度器当前的线程暂时不需要被调度,让调度器间CPU资源出让给其他线程, 注意与sleep的区别.

a.sleep: 会导致程序在一定时间内停止执行。不管在系统上发生了什么,您的线程将不会重新启动,直到至少经过了经过睡眠()的时间。

b.pthread_yield 通知操作系统您的线程正在工作,并且它可以将执行切换到另一个线程。但是,如果没有更高优先级的线程需要在那个时候工作,那么您的线程可能会立即重新启动。pthread_yield()只是一种礼貌的方式,可以让其他线程在需要时有机会运行。

2)参数:

3)例子:

static void *threadfunc1(void *parm)
 {				
	 while(1)
	 {
	       pthread_yield();
	       printf ("---hello world ---\n");
	  }
 }

---设置线程执行一次

int pthread_once (pthread_once_t *__once_control, void (*__init_routine) (void));

1)说明: 声明一个初始化函数,第一次调用pthread_once时它执行这个函数,以后的调用将被它忽略. 使用初值为PTHREAD_ONCE_INIT的once_control变量保证init_routine()函数在本进程执行序列中仅执行一次。

2)参数:

--__once_control: pthread_once_t 的一个控制变量,而且该控制变量必须使用PTHREAD_ONCE_INIT宏来静态的初始化。

--__init_routine: 与该 控制变量(pthread_once_t)相关联的所有初始化代码函数,现在线程可以在任何时间调用pthread_once, 指定一个指向一个控制变量的指针和指向相关初始化函数的指针。

3)例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <time.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/epoll.h>
#include <sys/poll.h>
			
#define CHECK_VARIABLE(l,r) do{if(0 != r){fprintf(stderr,"[%s], err:[%d]\n",l,r);break;}}while(0);

		
//宏初始化pthread_once_t控制变量
pthread_once_t once = PTHREAD_ONCE_INIT; 
pthread_mutex_t mutex ;
static const int globalVal = 10;

//pthread_once初始化函数
void threadOnceInit(){

	int ret = -1;
	ret = pthread_mutex_init(&mutex, NULL);
	CHECK_VARIABLE("pthread_mutex_init error",ret);
	puts("pthread_mutex_init success.");
	return;
}

//子线程执行函数
void* subThread(void* param){
	printf("subThread to do...\n");
	int ret = -1;
	ret = pthread_once(&once,threadOnceInit);

	CHECK_VARIABLE("pthread_once error",ret);
	ret = pthread_mutex_lock(&mutex);
	CHECK_VARIABLE("pthread_mutex_lock err",ret);
	printf("subThread has clocked the mutex. and globalVal is: [%d]\n",globalVal);
	ret = pthread_mutex_unlock(&mutex);
	CHECK_VARIABLE("pthread_mutex_unlock err.",ret);

	return  NULL;
}

int main(int argc,char **argv)
{
	pthread_t Tid;
	int ret = -1;
	ret = pthread_create(&Tid, NULL, subThread, NULL);
	CHECK_VARIABLE("pthread_create err.",ret);

	ret = pthread_once(&once,threadOnceInit);
	CHECK_VARIABLE("pthread_once err",ret);

	ret = pthread_mutex_lock(&mutex);
	CHECK_VARIABLE("pthread_mutex_lock",ret);

	printf("Main func has locked the mutex.\n");
	ret = pthread_mutex_unlock(&mutex);
	CHECK_VARIABLE("pthread_mutex_unlock",ret);

	ret = pthread_join(Tid,NULL);
	CHECK_VARIABLE("pthread_join",ret);
	return 0;
}

以上即为所有与线程相关的设置函数API接口。

发布于 2023-11-23 13:59?IP 属地四川

相关推荐

Linux两种光驱自动挂载的方法

环境:CentOS6.4西昆云服务器方式一修改fstab文件/etc/fstab是系统保存文件系统信息?静态文件,每一行描述一个文件系统;系统每次启动会读取此文件信息以确定需要挂载哪些文件系统。参...

linux系统运维,挂载和分区概念太难?在虚机下操作一次全掌握

虚拟机的好处就是可以模拟和学习生产环境的一切操作,假如我们还不熟悉磁盘操作,那先在虚机环境下多操作几次。这次来练习下硬盘扩容操作。虚拟机环境:centos8vm11linux设备命名规则在linux中...

Linux 挂载 NFS 外部存储 (mount 和 /etc/fstab)

mount:手工挂载,下次重启需再重新挂载,操作命令:mount-tnfs-ooptionsserver:/remote/export/local/directory上面命令中,本地目录...

在Linux中如何设置自动挂载特定文件系统(示例)

Linux...

Linux环境中的绑定挂载(bind mount)

简介:Linux中的mount命令是一个特殊的指令,主要用于挂载文件目录。而绑定挂载(bindmount)命令更为特别。mount的bind选项将第一个目录克隆到第二个。一个目录中的改变将会在...

Linux挂载CIFS共享 临时挂载 1. 首先

如何解决服务器存储空间不足的问题?大家好,欢迎回来。在上一期视频中,我为大家介绍了如何利用Linux挂载来扩容服务器存储空间。这一期视频,我将以Linux为例,教大家如何进行扩容。群辉使用的是Linu...

Linux 硬盘挂载(服务器重启自动挂载)

1、先查看目前机器上有几块硬盘,及已挂载磁盘:fdisk-l能够查看到当前主机上已连接上的磁盘,以及已经分割的磁盘分区。(下面以/dev/vdb磁盘进行分区、挂载为例,挂载点设置为/data)df...

linux 挂载磁盘

在Linux中挂载硬盘的步骤如下:...

笨小猪教您Linux磁盘挂载

本教程针对Linux系统比较熟悉或者想学习Linux基础的用户朋友,本教程操作起来比较傻瓜式,跟着步骤就会操作,本文使用的工具是XShell同时多多注意空格(文中会有提示)。【问答】什么是磁盘挂载?答...

Linux 磁盘挂载和docker安装命令

本篇给大家介绍Linux磁盘挂载和docker安装的相关内容,Linux服务器的操作是一个手熟的过程,一些不常用的命令隔断时间就忘记了,熟话说好记性不如烂笔头,还需在平时的工作中多练习记录。...

Linux设置开机自动挂载分区

有时候,我们在安装完Linux系统之后,可能在使用过程中添加硬盘或者分区进行使用,这时候就需要手动把磁盘分区挂载到某个路径,但是开机之后就会消失,需要重新挂载,非常麻烦,那么我们应该如何设置开机自动挂...

在linux挂载一个新硬盘的完整步骤

以下是在Linux中挂载新原始磁盘的完整步骤,包括分区、创建文件系统以及使用UUID在/etc/fstab中启动时挂载磁盘:将新的原始磁盘连接到Linux系统并打开电源。运行以下命令,...

Linux系统如何挂载exFAT分区

简介:Linux系统中不能像Windows系统那样自动识别加载新设备,需要手动识别,手动加载。Linux中一切皆文件。文件通过一个很大的文件树来组织,文件树的根目录是:/,从根目开始录逐级展开。这些文...

Linux系统挂载硬盘

fdisk-l查看可挂载的磁盘都有哪些df-h查看已经挂载的磁盘...

WSL2发布,如何在Win10中挂载Linux文件系统

WSL2是最新版本的架构,它为Windows子系统提供支持,使其能够在Windows上运行ELF64Linux二进制文件。通过最近的更新,它允许使用Linux文件系统访问存储在硬盘中的文件。如果你...

取消回复欢迎 发表评论: