调度算法要求:高资源利用率、高吞吐量、用户满意等原则。
进程调度所采用的算法是与整个系统的设计目标相一致的:
1.批处理系统:增加系统吞吐量和提高系统资源的利用率;
2.分时系统:保证每个分时用户能容忍的响应时间。
3.实时系统:保证对随机发生的外部事件做出实时响应
int pthread_setschedparam(pthread_t target_thread, int policy, const struct sched_param *param)
它主要用于设置线程的调用策略和优先级。
参数说明:
1. target_thread是使用pthread_create所获得的线程ID。
2. 线程的调度有三种策略:SCHED_OTHER、SCHED_RR和SCHED_FIFO。
Policy用于指明使用哪种策略。下面我们简单的说明一下这三种调度策略。
SCHED_OTHER
它是默认的线程分时调度策略,所有的线程的优先级别都是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调用策略。它使用最大运行时间来限制当前进程的运行,当运行时间大于等于最大运行时间的时候,当前线程将被切换并放置于相同优先级队列的最后。这样做的好处是其他具有相同级别的线程能在“自私“线程下执行。
linux内核的三种调度方法:
1,SCHED_OTHER 分时调度策略,
2,SCHED_FIFO 实时调度策略,先到先服务
3,SCHED_RR 实时调度策略,时间片轮转
实时进程将得到优先调用,实时进程根据实时优先级决定调度权值,分时进程则通过nice和counter值决定权值,nice越小,counter越大,被调度的概率越大,也就是曾经使用了cpu最少的进程将会得到优先调度。
SHCED_RR和SCHED_FIFO的不同:
当采用SHCED_RR策略的进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。放在队列尾保证了所有具有相同优先级的RR任务的调度公平。
SCHED_FIFO一旦占用cpu则一直运行。一直运行直到有更高优先级任务到达或自己放弃。
一个分时间片,一个一直占用
如果有相同优先级的实时进程(根据优先级计算的调度权值是一样的)已经准备好,FIFO时必须等待该进程主动放弃后才可以运行这个优先级相同的任务。而RR可以让每个任务都执行一段时间。
相同点:
RR和FIFO都只用于实时任务。
创建时优先级大于0(1-99)。
按照可抢占优先级调度算法进行。
就绪态的实时任务立即抢占非实时任务。
所有任务都采用linux分时调度策略时。
1,创建任务指定采用分时调度策略,并指定优先级nice值(-20~19)。
2,将根据每个任务的nice值确定在cpu上的执行时间(counter)。
3,如果没有等待资源,则将该任务加入到就绪队列中。
4,调度程序遍历就绪队列中的任务,通过对每个任务动态优先级的计算(counter+20-nice)结果,选择计算结果最大的一个去运行,当这个时间片用完后(counter减至0)或者主动放弃cpu时,该任务将被放在就绪队列末尾(时间片用完)或等待队列(因等待资源而放弃cpu)中。
5,此时调度程序重复上面计算过程,转到第4步。
6,当调度程序发现所有就绪任务计算所得的权值都为不大于0时,重复第2步。
所有任务都采用FIFO时,
1,创建进程时指定采用FIFO,并设置实时优先级rt_priority(1-99)。
2,如果没有等待资源,则将该任务加入到就绪队列中。
3,调度程序遍历就绪队列,根据实时优先级计算调度权值(1000+rt_priority),选择权值最高的任务使用cpu,该FIFO任务将一直占有cpu直到有优先级更高的任务就绪(即使优先级相同也不行)或者主动放弃(等待资源)。
4,调度程序发现有优先级更高的任务到达(高优先级任务可能被中断或定时器任务唤醒,再或被当前运行的任务唤醒,等等),则调度程序立即在当前任务堆栈中保存当前cpu寄存器的所有数据,重新从高优先级任务的堆栈中加载寄存器数据到cpu,此时高优先级的任务开始运行。重复第3步。
5,如果当前任务因等待资源而主动放弃cpu使用权,则该任务将从就绪队列中删除,加入等待队列,此时重复第3步。
所有任务都采用RR调度策略时
1,创建任务时指定调度参数为RR,并设置任务的实时优先级和nice值(nice值将会转换为该任务的时间片的长度)。
2,如果没有等待资源,则将该任务加入到就绪队列中。
3,调度程序遍历就绪队列,根据实时优先级计算调度权值(1000+rt_priority),选择权值最高的任务使用cpu。
4,如果就绪队列中的RR任务时间片为0,则会根据nice值设置该任务的时间片,同时将该任务放入就绪队列的末尾。重复步骤3。
5,当前任务由于等待资源而主动退出cpu,则其加入等待队列中。重复步骤3。
系统中既有分时调度,又有时间片轮转调度和先进先出调度
1,RR调度和FIFO调度的进程属于实时进程,以分时调度的进程是非实时进程。
2,当实时进程准备就绪后,如果当前cpu正在运行非实时进程,则实时进程立即抢占非实时进程。
3,RR进程和FIFO进程都采用实时优先级做为调度的权值标准,RR是FIFO的一个延伸。FIFO时,如果两个进程的优先级一样,则这两个优先级一样的进程具体执行哪一个是由其在队列中的位置决定的,这样导致一些不公正性(优先级是一样的,为什么要让你一直运行?),如果将两个优先级一样的任务的调度策略都设为RR,则保证了这两个任务可以循环执行,保证了公平。
3.param是struct sched_param类型的指针,它仅仅包含一个成员变sched_priority,指明所要设置的静态线程优先级。
#ifdef HAVE_SCHED_H
#include <sched.h>
#endif
void setCurrentThreadHighPriority(bool value)
{
// Start out with a standard, low-priority setup for the sched params.
struct sched_param sp;
bzero((void*)&sp, sizeof(sp));
int policy = SCHED_OTHER;
// If desired, set up high-priority sched params structure.
if (value)
{
// FIFO scheduler, ranked above default SCHED_OTHER queue
policy = SCHED_FIFO;
// The priority only compares us to other SCHED_FIFO threads, so we
// just pick a random priority halfway between min & max.
const int priority = (sched_get_priority_max(policy) +
sched_get_priority_min(policy)) / 2;
sp.sched_priority = priority;
}
// Actually set the sched params for the current thread.
if (0 == pthread_setschedparam(pthread_self(), policy, &sp))
{
printf("IO Thread #%d using high-priority scheduler!", pthread_self());
}
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
void * thr_fun(void *arg)
{
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("param:%d/n", param.sched_priority);
long long i;
while (1)
{
i++;
i *= 2;
}
pthread_exit(NULL);
}
int main(void)
{
int ret;
pthread_t tid;
pthread_attr_t attr;
int policy, inher;
struct sched_param param;
//初始化线程属性
pthread_attr_init(&attr);
//获取继承的调度策略
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_FIFO;//在Ubuntu9.10上需要root权限
//设置线程调度策略
ret = pthread_attr_setschedpolicy(&attr, policy);
if (ret!=0)
{
printf(" pthread_attr_setschedpolicy/n%s/n", strerror(ret));
exit(1);
}
param.sched_priority = 3;
//设置调度参数
ret = pthread_attr_setschedparam(&attr, ¶m);
if (ret!=0)
{
printf(" pthread_attr_setschedparam/n%s/n", strerror(ret));
exit(1);
}
//创建线程
ret = pthread_create(&tid, &attr, thr_fun, NULL);
if (ret!=0)
{
printf("pthread_create/n%s/n", strerror(ret));
exit(1);
}
while (1) {
printf("hello world/n");
}
pthread_join(tid, NULL);
pthread_exit(NULL);
}