【转】pthread设置线程的调度策略和优先级
线程的调度有三种策略:SCHED_OTHER、SCHED_RR和SCHED_FIFO。Policy⽤于指明使⽤哪种策略。下⾯我们简单的说明⼀下这三种调度策略。
all saintsSCHED_OTHER(是Linux默认的分时调度策略)
它是默认的线程分时调度策略,所有的线程的优先级别都是0,线程的调度是通过分时来完成的。简单地说,如果系统使⽤这种调度策略,程序将⽆法设置线程的优先级。请注意,这种调度策略也是抢占式的,当⾼优先级的线程准备运⾏的时候,当前线程将被抢占并进⼊等待队列。这种调度策略仅仅决定线程在可运⾏线程队列中的具有相同优先级的线程的运⾏次序。
SCHED_FIFO
它是⼀种实时的先进先出调⽤策略,且只能在超级⽤户下运⾏。这种调⽤策略仅仅被使⽤于优先级⼤于0的线程。它意味着,使⽤SCHED_FIFO的可运⾏线程将⼀直抢占使⽤SCHED_OTHER的运⾏线程J。此外SCHED_FIFO是⼀个⾮分时的简单调度策略,当⼀个线程变成可运⾏状态,它将被追加到对应优先级队列的尾部((POSIX 1003.1)。当所有⾼优先级的线程终⽌或者阻塞时,它将被运⾏。对于相同优先级别的线程,按照简单的先进先运⾏的规则运⾏。我们考虑⼀种很坏的情况,如果有若⼲相同优先级的线程
等待执⾏,然⽽最早执⾏的线程⽆终⽌或者阻塞动作,那么其他线程是⽆法执⾏的,除⾮当前线程调⽤如pthread_yield之类的函数,所以在使⽤SCHED_FIFO的时候要⼩⼼处理相同级别线程的动作。
SCHED_RR
鉴于SCHED_FIFO调度策略的⼀些缺点,SCHED_RR对SCHED_FIFO做出了⼀些增强功能。从实质上看,它还是SCHED_FIFO调⽤策略。它使⽤最⼤运⾏时间来限制当前进程的运⾏,当运⾏时间⼤于等于最⼤运⾏时间的时候,当前线程将被切换并放置于相同优先级队列的最后。这样做的好处是其他具有相同级别的线程能在“⾃私“线程下执⾏。
1.获得线程可以设置的最⾼和最低优先级,policy: 可以取三个值(SCHED_FIFO、SCHED_RR、
SCHED_OTHER)
int sched_get_priority_max(int policy);
int sched_get_priority_min(int policy);
注意:对于 SCHED_OTHER 策略,sched_priority 只能为 0。对于 SCHED_FIFO,SCHED_RR 策略,sched_priority 从 1 到 99。
2.设置和获取优先级通过以下两个函数
int pthread_attr_tschedparam(pthread_attr_t *attr, const struct sched_param *param);
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
param.sched_priority = 51; //设置优先级
了解sched_param结构体
struct sched_param
{
int __sched_priority; // 所要设定的线程优先级
};
//param是struct sched_param类型的指针,它仅仅包含⼀个成员变sched_priority,指明所要设置的静态线程优先级。
3.改变策略(静态改变策略和设置优先级)
int pthread_attr_tschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(pthread_attr_t *attr, int policy);
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
#include "errors.h"
void *thread_routine(void *arg)
{
int my_policy;
struct sched_param my_param;
#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && !defined(sun)
pthread_getschedparam(pthread_lf(), &my_policy, &my_param);
printf("thread_routine running at %s/%d\n",
(my_policy == SCHED_FIFO ? "FIFO"
: (my_policy == SCHED_RR ? "RR"
: (my_policy == SCHED_OTHER ? "OTHER"
: "unknown"))),
my_param.sched_priority);
#el宾语从句ppt
printf("thread_routine running\n");
#endif
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t thread_id;
pthread_attr_t thread_attr;
int thread_policy;
struct sched_param thread_param;
new什么意思int status, rr_min_priority, rr_max_priority;
pthread_attr_init(&thread_attr);
#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && !defined(sun)
pthread_attr_getschedpolicy(&thread_attr, &thread_policy);
pthread_attr_getschedparam(&thread_attr, &thread_param);//获取优先级
printf("Default policy is %s, priority is %d\n",
(thread_policy == SCHED_FIFO ? "FIFO"
: (thread_policy == SCHED_RR ? "RR"
: (thread_policy == SCHED_OTHER ? "OTHER"
: "unknown"))),
thread_param.sched_priority);
status = pthread_attr_tschedpolicy(&thread_attr, SCHED_RR);//改变策略
if(status != 0)
printf("Unable to t SCHED_RR policy.\n");
el
{
rr_min_priority = sched_get_priority_min(SCHED_RR);//看当前策略下能设置优先级的范围
if(rr_min_priority == -1)
errno_abort("Get SCHED_RR min priority");
rr_max_priority = sched_get_priority_max(SCHED_RR);
if(rr_max_priority == -1)
errno_abort("Get SCHED_RR max priority");
thread_param.sched_priority = (rr_min_priority + rr_max_priority)/2;//静态改变优先级(线程运⾏之前)
printf("SCHED_RR priority range is %d to %d: using %d\n",
rr_min_priority, rr_max_priority, thread_param.sched_priority);
pthread_attr_tschedparam(&thread_attr, &thread_param);
printf("Creating thread at RR/%d\n", thread_param.sched_priority);
pthread_attr_tinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED); //⽆论何时,当你需要控制⼀个线程的调度策略或优先级时,必须将inheritsched属性设置为PTHREAD_EXPLICIT_SCHED。
}
#el
printf("Priority scheduling not supported\n");
#endif
pthread_create(&thread_id, &thread_attr, thread_routine, NULL);
pthread_join(thread_id, NULL);
printf("Main exiting\n");
return 0;
wherever you will go
}
//运⾏结果
./sched_attr
Default policy is OTHER, priority is 0
SCHED_RR priority range is 1 to 99: using 50
Creating thread at RR/50
Main exiting
4.继承调度属性
我⼿动设置了调度策略或优先级时,必须显⽰的设置线程调度策略的inheritsched属性,因为pthread没有为inheritsched设置默认值。所以在改变了调度策略或优先级时必须总是
设置该属性。
int pthread_attr_tinheritsched(pthread_attr_t *attr, int inheritsched);
int pthread_attr_getinheritsched(pthread_attr_t *attr, int *inheritsched);wi fi是什么意思
第⼀个函数中inheritsched的取值为:PTHREAD_INHERIT_SCHED 或者 PTHREAD_EXPLICIT_SCHED。
前者为继承创建线程的调度策略和优先级,后者指定不继承调度策略和优先级,⽽是使⽤⾃⼰设置的调度策略和优先级。
⽆论何时,当你需要控制⼀个线程的调度策略或优先级时,必须将inheritsched属性设置为PTHREAD_EXPLICIT_SCHED。
总结:
1)调度策略和优先级是分开来描述的。前者使⽤预定义的SCHED_RR、SCHED_FIFO、SCHED_OTHER,后者是通过结果体struct sched_param给出的。
2)这些设置调度策略和优先级的函数操作的对象是线程的属性pthread_attr_t,⽽不是直接来操作线程的调度策略和优先级的。函数的第⼀个参数都是pthread_attr_t。
5.直接设置正在运⾏的线程的调度策略和优先级(动态设置线程的调度策略和优先级)
前⾯的那些函数只能通过线程的属性对象 pthread_attr_t 来设置线程的调度策略和优先级,不能够直接设置正在运⾏的线程的调度策略和优先级。下⾯的函数可以直接设置:
int pthread_tschedparam(pthread_t thread, int policy, const struct sched_param *param);
int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param);
// 在成功完成之后返回零。其他任何返回值都表⽰出现了错误。如果出现以下任⼀情况,pthread_tschedparam() 函数将失败并返回相应的值--EINVAL所设置属性的值⽆效。ENOTSUP--尝试将该属性设置为不受⽀持的值。失败条件:
int pthread_tschedparam:thread参数所指向的线程不存在
int pthread_getschedparam:1.参数policy或同参数policy关联的调度参数之⼀⽆效;2.数policy或调度参数之⼀的值不被⽀持;
3.调⽤线程没有适当的权限来设置指定线程的调度参数或策略;
4.参数thread指向的线程不存在;
5.实现不允许应⽤程序将参数改动为特定的值
注意:当pthread_tschedparam函数的参数 policy == SCHED_RR 或者 SCHED_FIFO 时,程序必须要在超级⽤户下运⾏
pthread_tschedparam 函数改变在运⾏线程的调度策略和优先级肯定就不⽤调⽤函数来设置inheritsched属性了:
pthread_attr_tinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED); 因为该函数设置的对象是pthread_attr_t
/*
* sched_thread.c
* Demonstrate dynamic scheduling policy u.
*/
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
#include "errors.h"
#define THREADS 5
typedef struct thread_tag {
int index;
pthread_t id;
} thread_t;
thread_t threads[THREADS];
int rr_min_priority;
void *thread_routine(void *arg)
{
thread_t *lf = (thread_t *)arg;
struct sched_param my_param;
int my_policy;
int status;
my_param.sched_priority = rr_min_priority + lf->index;
if(pthread_tschedparam(lf->id, SCHED_RR, &my_param) != 0)//线程运⾏时设置策略和优先值
printf("pthread_tschedparam failed\n");
pthread_getschedparam(lf->id, &my_policy, &my_param);
printf("thread_routine %d running at %s/%d\n",
lf->index,
(my_policy == SCHED_FIFO ? "FIFO"
: (my_policy == SCHED_RR ? "RR"
vinet: (my_policy == SCHED_OTHER ? "OTHER"
:
"unknown"))),
my_param.sched_priority);
return NULL;
}
int main(int argc, char *argv[])
{
新年英语祝福语int count;
rr_min_priority = sched_get_priority_min(SCHED_RR);
if(rr_min_priority == -1){
errno_abort("Get SCHED_RR min priority");
}hassan
for(count = 0; count < THREADS; count++){
threads[count].index = count;
pthread_create(&threads[count].id, NULL,
thread_routine, (void *)&threads[count]);
}
for(count = 0; count < THREADS; count++){
pthread_join(threads[count].id, NULL);
}
printf("Main exiting\n");
return 0;
}
/
/运⾏结果
gcc -Wall -lpthread -o sched_thread sched_thread.c
./sched_thread
pthread_tschedparam failed
pthread_tschedparam failed
pthread_tschedparam failed
thread_routine 1 running at OTHER/0
thread_routine 3 running at OTHER/0
pthread_tschedparam failed
pthread_tschedparam failed
thread_routine 2 running at OTHER/0
thread_routine 4 running at OTHER/0
thread_routine 0 running at OTHER/0
Main exiting
//以上失败,⼀下运⾏⽤:sudo ./sched_thread (输⼊密码)时,函数 pthread_tschedparam(lf->id, SCHED_RR, &my_param) 调⽤成功。将SCHED_RR换成SCHED_FIFO,结果也是⼀样的。digdeep@ubuntu:~/pthread/learnthread$ sudo ./sched_thread
[sudo] password for digdeep:
thread_routine 1 running at RR/2
thread_routine 3 running at RR/4
thread_routine 2 running at RR/3
thread_routine 0 running at RR/1陶缸绘
thread_routine 4 running at RR/5
Main exitingwhite是什么意思
digdeep@ubuntu:~/pthread/learnthread$
它有很多改进的地⽅,⽐如可以使⽤虚优先级(在程序中加⼊虚实影射表)等