创建线程:
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, ¶m);
例子:
#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, ¶m); printf("Thread1:policy(%d), PRI(%d) ", policy, param.__sched_priority); for(int i=1;i<10;i++) { for(int j=1;j<5000000;j++) { } printf("thread 1 "); } printf("Pthread 1 exit "); } void *Thread2(void *arg) { sleep(1); int policy; struct sched_param param; pthread_getschedparam(pthread_self(), &policy, ¶m); printf("Thread2:policy(%d), PRI(%d) ", policy, param.__sched_priority); for(int i=1;i<10;i++) { for(int j=1;j<5000000;j++) { } printf("thread 2 "); } printf("Pthread 2 exit "); } void *Thread3(void *arg) { sleep(1); int policy; struct sched_param param; pthread_getschedparam(pthread_self(),&policy,¶m); printf("Thread3:policy(%d), PRI(%d) ", policy, param.__sched_priority); for(int i=1;i<10;i++) { for(int j=1;j<5000000;j++) { } printf("thread 3 "); } printf("Pthread 3 exit "); } int main() { int i; i = getuid(); if(i==0) printf("The current user is root "); else printf("The current user is not root "); 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,¶m); pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED);//要使优先级其作用必须要有这句话 param.sched_priority = 21; pthread_attr_setschedpolicy(&attr2,SCHED_RR); pthread_attr_setschedparam(&attr2,¶m); 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),而且用完了它的时间片。
基于时间片轮转的实时进程是,不是真正的改变进程的优先级,而是改变进程的基本时间片的长度。所以基于时间片轮转的进程调度,并不能保证高优先级的进程先运行。