Linux下 线程优先级 和 线程调度策略 设置

本文详细介绍了在Linux环境下如何创建线程,使用pthread_create函数,以及如何通过pthread_attr_t设置线程的优先级、调度策略和CPU绑定。重点讲解了SCHED_OTHER、SCHED_FIFO和SCHED_RR三种调度策略的特点。
摘要由CSDN通过智能技术生成

参考连接:https://blog.csdn.net/weixin_44845857/article/details/118409858

Linux下 线程优先级 和 线程调度策略 设置

线程的创建

线程创建的接口函数 pthread_create()

#include <pthread.h>
int pthread_create(
                 pthread_t *restrict tidp,   //新创建的线程ID指向的内存单元。
                 const pthread_attr_t *restrict attr,  //线程属性,默认为NULL
                 void *(*start_rtn)(void *), //新创建的线程运行的函数
                 void *restrict arg //默认为NULL。如果线程运行的函数需要参数,将参数放入结构中并将地址作为arg传入。
                );

线程属性结构体

线程属性的设置是根据实际的需要来设置的。默认属性下, 可以解决大部分开发时遇到的问题。
如果我们需要对线程提出更高的性能要求,就可以通过线程属性来设置 线程的优先级,线程的调度策略以及线程栈的大小等来满足。

下面是线程属性结构体的详解

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

线程调度策略的设置

线程优先级的设置 由线程属性来控制。linux 内核提供了很多接口函数来设置 pthread_attr_t 结构体。修改后作为pthread_create()的第二个参数 传递。

//线程调度策略设置和获取函数,pthread_attr_t 为线程属性, policy 就是 线程调度策略

// policy 参数一般由3种 SCHED_OTHER, SCHED_FIFO, SCHED_RR.
int pthread_attr_setschedpolicy(pthread_attr_*, int policy)
//获取线程属性,将属性值赋给policy 
int pthread_attr_getschedpolicy(const pthread_attr_t *, int * policy)

SCHEAD_OTHER : 分时调度策略。线程默认调度策略,不区分优先级,该调度方式通过分时来完成的。
它旨在确保每个分时调度的线程都获得相同多的处理器时间。
请注意,这种调度策略也是抢占式的,当高优先级的线程准备运行的时候,当前线程将被抢占并进入等待队列。
例如:当实时线程准备就绪后,若当前运行的线程是分时线程,则实时线程会立即抢占分时线程。

SCHED_FIFO : 实时调度策略,先进先出原则,这种调度方式有优先级之分,并且无时间片概念。
于该调度策略时,高优先级的进程将会一直占用CPU 直到有更高优先级的线程出现,将线程设置为该调度策略的时候需要超级用户模式。当实时线程处于就绪状态时,当前使用cpu的线程优先级比它低时,会立即抢占。

SCHED_RR : 实时调度策略,时间片轮转。 在SCHED_FIFO的基础上加入了时间片。
当线程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。同样可以被高优先级抢占。

线程优先级的设置

//线程优先级设置和获取函数
int pthread_attr_setschedparam(pthread_attr_t *,const struct sched_param *);
int pthread_attr_getschedparam(const pthread_attr_t *,struct sched_param *);

结构体 sched_param 中 只有一项 __sched_priority 代表优先级,值越大优先级越高。

//获取系统调度策略的最大最小优先级
int sched_get_priority_max( int policy );
int sched_get_priority_min( int policy );

//获取和设置线程的继承性 默认是 PTHREAD_INHERIT_SCHED 
int pthread_attr_getinheritsched(const pthread_attr_t * attr,int *inheritsched);
int pthread_attr_setinheritsched(pthread_attr_t * attr,int inheritsched);

//例如:
{
		int s;
		pthread_attr_t attr;
		struct sched_param param;
		pthread_attr_init(&attr);//初始化线程属性
		//获取线程的继承性 默认是 PTHREAD_INHERIT_SCHED 
		s = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
	   	s = pthread_attr_setschedpolicy(&attr, SCHED_RR);//设置调度模式
	    s = sched_get_priority_max(SCHED_RR);            //获取RR调度模式下的最大线程优先级
	    param.sched_priority = s;                        //设置线程优先级
	    s = pthread_attr_setschedparam(&attr, &param);	//将优先级添加到线程属性中
}

线程绑定CPU

//设置和获取当前线程绑定的CPU ID
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);
//从函数名以及参数名都很明了,唯一需要点解释下的可能就是cpu_set_t这个结构体了。这个结构体的理解类似于select中的fd_set,可以理解为cpu集,也是通过约定好的宏来进行清除、设置以及判断:
//初始化,设为空
void CPU_ZERO (cpu_set_t *set); 
//将某个cpu加入cpu集中 
void CPU_SET (int cpu, cpu_set_t *set); 
//将某个cpu从cpu集中移出 
void CPU_CLR (int cpu, cpu_set_t *set); 
//判断某个cpu是否已在cpu集中设置了 
int CPU_ISSET (int cpu, const cpu_set_t *set);

代码示例

#define _GNU_SOURCE
#include <stdio.h>
#include <math.h>
#include <pthread.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sched.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>




void *myThread1(void){
	while(1)
	{
		printf("This is the 1th\n");		
		sleep(1);
	}
}



void *myThread2(void){
	while(1)
	{
		printf("This is the 2th pthread\n");
		sleep(1);
	}


}

void *myThread3(void)
{
	struct timeval tv;
	while(1){
			gettimeofday(&tv,NULL);
			printf("change priority befor millisecond:%ld\n",tv.tv_sec*1000 + tv.tv_usec/1000);

			sleep(1);
    	}
	
}

void myThread4(void)
{
	struct timeval tv;
	while(1){
			gettimeofday(&tv,NULL);
			printf("change priority after millisecond:%ld\n",tv.tv_sec*1000 + tv.tv_usec/1000);
			sleep(1);
    	}
	
}

void *thread_func(void *arg){   
	cpu_set_t cpuset;
	int policy, ret;  
    struct sched_param param;  
    //获取线程调度参数   
    ret = pthread_getschedparam(pthread_self(), &policy, &param);  
    if(ret!=0){  
        printf("pthread_getschedparam %s\n", strerror(ret) );  
        exit(1);  
    }  
    if (policy == SCHED_FIFO){  
        printf("policy:SCHED_FIFO\n");  
    }  
    else if (policy == SCHED_OTHER){  
        printf("policy:SCHED_OTHER\n");  
    }  
    else if (policy == SCHED_RR){  
        printf("policy:SCHED_RR\n");  
    }  
    printf("thread_func priority is %d\n", param.sched_priority);  

	CPU_ZERO(&cpuset);
	CPU_SET(1, &cpuset); /* cpu 1 is in cpuset now */		

	/* bind process to processor 1 */
	if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) !=0) {
		perror("pthread_setaffinity_np");
	}

	printf("Core 1 is running! this pthread PID is %d\n",gettid());

	myThread4();
}

int main(int argc, char *argv[]){ 

	pthread_t my_thread;
	time_t startwtime, endwtime;
	pthread_t id1,id2,id3;
	int ret = 0;
	pthread_attr_t attr;
	struct sched_param sp;
	int policy ,inher;
	int rs;

	bzero((void*)&sp,sizeof(sp));

	pid_t pid = gettid();//获取进程PID
	pthread_t tid = pthread_self(); //获取当前线程ID
	printf("main: pid=%d, tid=%lu\n", pid, tid);
	/* 在默认情况下通过pthread_create函数创建的线程是非分离属性的,
	 * 由pthread_create函数的第二个参数决定,
	 * 在非分离的情况下,当一个线程结束的时候,
	 * 它所占用的系统资源并没有完全真正的释放,也没有真正终止。
	 * 只有在pthread_join函数返回时,该线程才会释放自己的资源。
	 * 或者是设置在分离属性的情况下,一个线程结束会立即释放它所占用的资源。
	 * pthread_join()函数会一直阻塞调用线程,直到指定的线程终止。
	 * 当pthread_join()返回之后,应用程序可回收与已终止线程关联的任何数据存储空间。
	 * 但是,同时需要注意,一定要和上面创建的某一线程配套使用,这样还可以起到互斥的作用。
	 * 否则多线程可能抢占CPU资源,导致运行结果不确定。
	 */

	rs = pthread_attr_init(&attr);
	assert(rs == 0);

	//获取继承的调度策略   
    ret = pthread_attr_getinheritsched(&attr, &inher);  
    if (ret!=0)  
    {  
        printf("pthread_attr_getinheritsched\n%s\n", strerror(ret));  
        exit(1);  
    }  
    //打印继承的调度策略
    if (inher == PTHREAD_EXPLICIT_SCHED)   
    {  
        printf("PTHREAD_EXPLICIT_SCHED\n");  
    }  
    else if (inher == PTHREAD_INHERIT_SCHED)   
    {     
        printf("PTHREAD_INHERIT_SCHED\n");  
        inher = PTHREAD_EXPLICIT_SCHED;  
    }  
    //设置继承的调度策略   
    //必需设置inher的属性为 PTHREAD_EXPLICIT_SCHED,否则设置线程的优先级会被忽略   
    ret = pthread_attr_setinheritsched(&attr, inher);  
    if (ret!=0)  
    {  
        printf("pthread_attr_setinheritsched\n%s\n", strerror(ret));  
        exit(1);  
    }  

	policy = SCHED_RR; //需要超级用户权限
	pthread_attr_setschedpolicy( &attr, policy );//设置 调度策略为SCHED_RR
	assert( rs == 0 );
	

	const int priority = 51;	//设置优先级 为51
	sp.__sched_priority = priority;

	//if(0 == pthread_setschedparam(pthread_self(),policy,&sp)){
	if(pthread_attr_setschedparam(&attr,&sp) != 0){//设置优先级
		printf("pthread set sched priority failed\n");
	}

	if (pthread_create(&my_thread, &attr, thread_func,NULL) != 0) {
		perror("pthread_create failed\n");
	}

	ret = pthread_create(&id1,NULL,(void*)myThread1,NULL);
	if(ret){
		printf("cread pthread1 failed\n ");
		return -1;
	}

	ret = pthread_create(&id2,NULL,(void*)myThread2,NULL);
	if(ret){
		printf("cread pthread2 failed\n ");
		return -1;
	}
	ret = pthread_create(&id3,NULL,(void*)myThread3,NULL);
	if(ret){
		printf("cread pthread3 failed\n ");
		return -1;
	}

	pthread_join(my_thread,NULL);
	pthread_join(id1,NULL);
	pthread_join(id2,NULL);
	pthread_join(id3,NULL);
	
	
	return 0;
}

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值