一个线程调度策略的例子

创建线程:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void*), void *arg);

接下来要说的是:创建线程后,设置线程优先级的问题。

获取/设置当前线程使用的调度策略:
函数: int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); //主要使用sched_param.__sched_priority
成功返回0,否则返回-1
policy一般为:SCHED_FIFO, SCHED_RR 和 SCHED_OTHER。其定义出处见sched.h
/* Scheduling algorithms. */
#define SCHED_OTHER 0
#define SCHED_FIFO 1
#define SCHED_RR 2
#ifdef __USE_GNU
# define SCHED_BATCH 3
# define SCHED_IDLE 5

系统创建线程时,默认的线程是SCHED_OTHER。
(1)注意:有时候你会发现获取调度策略返回-1,这种现象跟编译方式有关,请在编译选项上加上-lpthread

 

获取某一种调试策略下优先级极值:即获得线程可以设置的最高和最低优先级
int sched_get_priority_max(int policy);
int sched_get_priority_min(int policy);
说明:
SCHED_OTHER是不支持优先级使用的,
而SCHED_FIFO和SCHED_RR支持优先级的使用,他们分别为1和99,数值越大优先级越高。
三种策略下的极值如下:
SCHED_OTHER: (0-0)
SCHED_FIFO: (1-99)
SCHED_RR: (1-99)

结论:
如果程序控制线程的优先级,一般是用pthread_attr_getschedpolicy来获取系统使用的调度策略,
如果是SCHED_OTHER的话,表明当前策略不支持线程优先级的使用,否则可以。当然所设定的优先级范围必须在最大和最小值之间。
我们可以通过sched_get_priority_max和sched_get_priority_min来获取。
理论上,可以通过int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);来设定自己所需的调度策略

再接下来,在允许使用线程优先级别的时候,如何设置优先级别?
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);
其中struct sched_param中的__sched_priority用来设定线程的优先级

(2)int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param);
int pthread_attr_setschedparam(pthread_attr_t *restrict attr, const struct sched_param *restrict param);
前者是修改现在正在执行中的线程,具体地说,就是在pthread_create之后才能使用。
后者是修改将要创建的线程的参数,在pthread_create就要使用了。


概念:策略优先级:
函数:int pthread_getschedparam (pthread_t thread, int policy, struct sched_param *param)
举例,在线程内部编码如下:
int policy = 0;
struct sched_param param;
pthread_getschedparam(pthread_self(),&policy, &param);

 

例子:

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

void *Thread1(void *arg)
{
        sleep(1);
        int policy;
        struct sched_param param;
        pthread_getschedparam(pthread_self(), &policy, &param);
        printf("Thread1:policy(%d), PRI(%d)\n", policy, param.__sched_priority);

        for(int i=1;i<10;i++)
        {
                for(int j=1;j<5000000;j++)
                {
                }
                printf("thread 1\n");
        }
        printf("Pthread 1 exit\n");
}

void *Thread2(void *arg)
{
        sleep(1);
        int policy;
        struct sched_param param;
        pthread_getschedparam(pthread_self(), &policy, &param);
        printf("Thread2:policy(%d), PRI(%d)\n", policy, param.__sched_priority);

        for(int i=1;i<10;i++)
        {
                for(int j=1;j<5000000;j++)
                {

                }
                printf("thread 2\n");
        }
        printf("Pthread 2 exit\n");
}

void *Thread3(void *arg)
{
        sleep(1);
        int policy;
        struct sched_param param;
        pthread_getschedparam(pthread_self(),&policy,&param);
        printf("Thread3:policy(%d), PRI(%d)\n", policy, param.__sched_priority);

        for(int i=1;i<10;i++)
        {
                for(int j=1;j<5000000;j++)
                {
                }
                printf("thread 3\n");
        }
        printf("Pthread 3 exit\n");
}


int main()
{
        int i;
        i = getuid();
        if(i==0)
                printf("The current user is root\n");
        else
                printf("The current user is not root\n");

        pthread_t tid1,tid2,tid3;
        struct sched_param param;

        pthread_attr_t attr3,attr2,attr1;

        //thread attr init
        pthread_attr_init(&attr1);
        pthread_attr_init(&attr2);

        //thread attr setting
        param.sched_priority = 51;
        pthread_attr_setschedpolicy(&attr1,SCHED_RR);
        pthread_attr_setschedparam(&attr1,&param);
        pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED);//要使优先级其作用必须要有这句话

        param.sched_priority = 21;
        pthread_attr_setschedpolicy(&attr2,SCHED_RR);
        pthread_attr_setschedparam(&attr2,&param);
        pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED);

        pthread_attr_init(&attr3);

        //thread create
        pthread_create(&tid3,&attr3, Thread3,NULL);
        pthread_create(&tid2,&attr2,Thread2,NULL);
        pthread_create(&tid1,&attr1,Thread1,NULL);

        //thread wait
        pthread_join(tid3,NULL);
        pthread_join(tid2,NULL);
        pthread_join(tid1,NULL);

        //thread desory attr
        pthread_attr_destroy(&attr1);
        pthread_attr_destroy(&attr2);

        return 0;
}

 

运行结果:g++ 2-sched.cpp -lpthread

[root@localhost thread]# ./a.out 
The current user is root
Thread1:policy(2), PRI(51)
Thread2:policy(2), PRI(21)
Thread3:policy(0), PRI(0
thread 2
thread 1
thread 3
thread 1
thread 2
thread 3
thread 1
thread 2
thread 3
thread 1
thread 2
thread 3
thread 1
thread 2
thread 3
thread 1
thread 2
thread 3
thread 1
thread 2
thread 3
thread 1
thread 2
thread 3
thread 1
Pthread 1 exit
thread 2
Pthread 2 exit
thread 3
Pthread 3 exit

 

结论:

这 里我们可以看到,由于线程3的调度策略是SCHED_OTHER,而线程2的调度策略是SCHED_RR,所以,在Thread3中,线程3被线程1,线 程2给抢占了。由于线程1的优先级大于线程2的优先级,所以,在线程1以先于线程2运行,不过,这里线程2有一部分代码还是先于线程1运行了。
我原以为,只要线程的优先级高,就会一定先运行,其实,这样的理解是片面的,特别是在SMP的PC机上更会增加其不确定性。
其实,普通进程的调度,是CPU根据进程优先级算出时间片,这样并不能一定保证高优先级的进程一定先运行,只不过和优先级低的进程相比,通常优先级较高的 进程获得的CPU时间片会更长而已。其实,如果要想保证一个线程运行完在运行另一个线程的话,就要使用多线程的同步技术,信号量,条件变量等方法。而不是绝对依靠优先级的高低,来保证。
不过,从运行的结果上,我们可以看到,调度策略为SCHED_RR的线程1,线程2确实抢占了调度策略为SCHED_OTHER的线程3。这个是可以理解的,由于SCHER_RR是实时调度策略。
只有在下述事件之一发生时,实时进程才会被另外一个进程取代。
(1) 进程被另外一个具有更高实时优先级的实时进程抢占。
(2) 进程执行了阻塞操作并进入睡眠
(3)进程停止(处于TASK_STOPPED 或TASK_TRACED状态)或被杀死。
(4)进程通过调用系统调用sched_yield(),自愿放弃CPU 。
(5)进程基于时间片轮转的实时进程(SCHED_RR),而且用完了它的时间片。

   基于时间片轮转的实时进程是,不是真正的改变进程的优先级,而是改变进程的基本时间片的长度。所以基于时间片轮转的进程调度,并不能保证高优先级的进程先运行。

posted @ 2014-10-17 00:54  咚咚锵锵  阅读(1434)  评论(1编辑  收藏  举报