参考连接: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, ¶m); //将优先级添加到线程属性中
}
线程绑定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, ¶m);
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;
}