一个线程调度策略的例子

创建线程:
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

[[email protected] 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),而且用完了它的时间片。

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

时间: 2024-08-09 22:02:47

一个线程调度策略的例子的相关文章

Delphi多线程的OnTerminate属性(附加一个关于临界区线程同步的例子)

首先看TThread源码中关于OnTerminate的代码: public .... property OnTerminate: TNotifyEvent read FOnTerminate write FOnTerminate; ... end; 再看Delphi自带的帮助手册中对于OnTerminate的解释: Occurs after the thread's Execute method has returned and before the thread is destroyed. p

linux线程调度策略

目录 linux线程调度策略 linux线程调度策略 这是一篇关于线程调度的非常好的资料,翻译自shed 从Linux 2.6.23开始,默认的调度器为CFS,即"完全公平调度器"(Completely Fair Scheduler).CFS调度器取代了之前的"O(1)"调度器. Scheduling policies 内核模块使用调度器来决定下一个CPU时钟周期执行的线程.每个线程都包含一个调度策略以及一个静态的调度优先级sched_priority,调度器根据系

二 Java利用等待/通知机制实现一个线程池

接着上一篇博客的 一Java线程的等待/通知模型 ,没有看过的建议先看一下.下面我们用等待通知机制来实现一个线程池 线程的任务就以打印一行文本来模拟耗时的任务.主要代码如下: 1  定义一个任务的接口. 1 /* 2 * 任务的接口 3 */ 4 public interface Task { 5 void doSomething(); 6 } 2  实现一个具体的任务. 1 /* 2 * 具体的任务 3 */ 4 public class PrintTask implements Task{

Android实战技巧之四十三:终止一个线程引起的

这是一道老牌面试题.通常面试官会问你对Java线程的了解,然后再问此问题. 从理论到实践,这是一条好路子. 线程是操作系统实现多任务的一种方式,可以理解为线程是一个任务的执行单元.比如Android系统中每个App都会有自己的主线程,同时还可以创建worker thread"并行"为我们工作. Java中创建新线程的方法 Java对线程(Thread)提供了语言级的支持(依托虚拟机吧).java.lang包下有Thread类和Runnable接口,都可以替你完成创建新线程的工作. 1.

Java一个简单的死锁例子

内容:一个简单的死锁例子,大概的思路:两个线程A和B,两把锁X和Y,现在A先拿到锁X,然后sleep()一段时间,我们知道sleep()是不会释放锁资源的.然后如果这段时间线程B拿到锁Y,也sleep()一段时间的话,那么等到两个线程都醒过来的话,那么将互相等待对方释放锁资源而僵持下去,陷入死锁.flag的作用就是让A和B获得不同的锁. public class TestDeadLock { public void run() { MyThread mt = new MyThread(); ne

Qt学习之如何启动和终止一个线程

先来给出每个文件的相关代码然后再加以分析 Cpp代码   //*************dialog.h**************// #ifndef DIALOG_H #define DIALOG_H #include <QDialog> #define MAXSIZE 5  //最大的线程数 class QDialogButtonBox; class QProgressBar; class QPushButton; class WorkThread; class ThreadDlg : 

13 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件  queue队列 生产者消费者模型 Queue队列 开发一个线程池

本节内容 操作系统发展史介绍 进程.与线程区别 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者消费者模型 Queue队列 开发一个线程池 进程 语法 进程间通讯 进程池 操作系统发展史 手工操作(无操作系统) 1946年第一台计算机诞生--20世纪50年代中期,还未出现操作系统,计算机工作采用手工操作方式. 手工操作程序员将对应于程序和数据的已穿孔的纸带(或卡片)装入输入机,然后启动输入机把

Java并发(基础知识)—— 创建、运行以及停止一个线程

0.介绍 在计算机世界,当人们谈到并发时,它的意思是一系列的任务在计算机中同时执行.如果计算机有多个处理器或者多核处理器,那么这个同时性是真实发生的:如果计算机只有一个核心处理器那么就只是表面现象. 现代所有的操作系统都允许并发地执行任务.你可以在听音乐和浏览网页新闻的同时阅读邮件,我们说这种并发是进程级别的并发.而且在同一进程内,也会同时有多种任务,这些在同一进程内运行的并发任务称之为线程. 在这里我们要讨论的是线程级并发.Java提供了Thread类,使我们能够在一个Java进程中运行多个线

易语言怎样写双线程?一个线程循环找图。一个线程循环按键F2。

易语言怎样写双线程? 一个线程循环找图.一个线程循环按键F2. // .程序集变量 参数, 整数型 .程序集变量 线程句柄1, 整数型 .程序集变量 线程句柄2, 整数型 启动线程 (&子程序1, 参数,线程句柄1) 启动线程 (&子程序2, ,线程句柄2) // .子程序 子程序1 .参数 参数1, 整数型 信息框 (参数1, 0, ) 信息框 (“这是线程1的例子”, 0, ) // .子程序 子程序2 信息框 (“这是线程2的例子”, 0, ) // // 注意: 凡调用到COM接口