基于嵌入式操作系统VxWorks的多任务并发程序设计(3)――任务调度

简介:



基于嵌入式操作系统VxWorks的多任务并发程序设计(3

――任务调度
作者:宋宝华  e-mail:[email]21cnbao@21cn.com[/email] 出处:软件报
VxWorks 支持两种方式的任务调度:
1 )基于优先级的抢占调度 (Preemptive Priority Based Scheduling)
抢占是指正在执行的任务可以被打断,让另一个任务运行,它可以提高应用程序对异步事件的响应能力。基于优先级的抢占调度是最常见的抢占机制,用户任务被分配一个优先级,操作系统内核总是调度优先级最高的就绪任务运行于 CPU 。当系统正在执行低优先级任务时,一旦有更高优先级的任务准备就绪, OS 内核会立即进行任务的上下文切换。
VxWorks Wind 内核划分优先级为 256  级( 0~255 )。优先级 0 为最高优先级,优先级 255 为最低。当任务被创建时,系统根据用户指定的值分配任务优先级。 VxWorks 的任务优先级也可以是动态的,它们能在系统运行时被用户使用系统调用 taskPrioritySet() 来加以改变。
        2 )时间片轮转调度( Round-Robin Scheduling)
        时间片轮转调度指的是操作系统分配一定的时间间隔(时间片),使每个任务轮流运行于 CPU 。在 VxWorks 中,对于优先级相同的多个任务,如果状态为 ready ,则其可以通过时间片轮转方式公平享有 CPU 资源。
        轮转调度法给处于就绪态的每个同优先级的任务分配一个相同的执行时间片,时间片的大小可由系统调用 KernelTimeSlice 指定。为对轮转调度进行支持,系统给每个任务提供一个运行时间计数器,任务运行时每一时间滴答计数器加 1 。一个任务用完时间片之后, OS 停止执行该任务,将它放入就绪队列尾部,并将其运行时间计数器置零。接着, OS 执行就绪队列中的下一个任务。

6. 任务调度

 

6.1时间片轮转调度

我们来看一个具体的例子,在这个程序中,用户启动了三个优先级相同的任务,并通过对 kernelTimeSlice(TIMESLICE) 的调用启动了时间片轮转调度。
1 :时间片轮转调度
/* includes */
#include "vxWorks.h"
#include "taskLib.h"
#include "kernelLib.h"
#include "sysLib.h"
 
/* function prototypes */
void taskOne(void);
void taskTwo(void);
void taskThree(void);
 
/* globals */
#define ITER1 100
#define ITER2 10
#define PRIORITY 101
#define TIMESLICE sysClkRateGet()
#define LONG_TIME 0xFFFFFFL
 
void sched(void) /* function to create the three tasks */
{
  int taskIdOne, taskIdTwo, taskIdThree;
 
  if (kernelTimeSlice(TIMESLICE) == OK)
  /* turn round-robin on */
    printf("\n\n\n\n\t\t\tTIMESLICE = %d seconds\n\n\n", TIMESLICE / 60);
 
  /* spawn the three tasks */
  if ((taskIdOne = taskSpawn("task1", PRIORITY, 0x100, 20000, (FUNCPTR)taskOne,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    printf("taskSpawn taskOne failed\n");
  if ((taskIdTwo = taskSpawn("task2", PRIORITY, 0x100, 20000, (FUNCPTR)taskTwo,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    printf("taskSpawn taskTwo failed\n");
  if ((taskIdThree = taskSpawn("task3", PRIORITY, 0x100, 20000, (FUNCPTR)
    taskThree, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    printf("taskSpawn taskThree failed\n");
 
}
 
void taskOne(void)
{
  unsigned int i, j;
  for (i = 0; i < ITER1; i++)
  {
    for (j = 0; j < ITER2; j++)
      printf("task1\n");
    /* log messages */
    for (j = 0; j < LONG_TIME; j++)
      ;
    /* allow time for context switch */
  }
}
 
void taskTwo(void)
{
  unsigned int i, j;
  for (i = 0; i < ITER1; i++)
  {
    for (j = 0; j < ITER2; j++)
      printf("task2\n");
    /* log messages */
    for (j = 0; j < LONG_TIME; j++)
      ;
    /* allow time for context switch */
  }
}
 
void taskThree(void)
{
  unsigned int i, j;
  for (i = 0; i < ITER1; i++)
  {
    for (j = 0; j < ITER2; j++)
      printf("task3\n");
    /* log messages */
    for (j = 0; j < LONG_TIME; j++)
      ;
    /* allow time for context switch */
  }
}
程序运行输出:一会儿输出一些“ task1 ”,一会儿输出一些“ task2 ”,再一会儿输出一些“ task3 ”。每次输出了某任务的一部分内容后,就开始输出另一任务的内容,这说明了 task1 task2 task3 再进行时间片轮转切换。
对于任务的上下文切换,我们可以使用 WindView 进行观察。 WindView 是一个图形化的动态诊断和分析工具,它可以向开发者提供目标机硬件上所运行应用程序的许多详细情况。下图显示了使用 WindView 获取的上述程序的运行结果:
kernelTimeSlice() 的函数原型为:
STATUS kernelTimeSlice (int ticks /* time-slice in ticks or 0 to disable round-robin */ );
程序中的 kernelTimeSlice(TIMESLICE) 展开后为 kernelTimeSlice(sysClkRateGet()) ,即每秒钟进行一次轮转。如果 kernelTimeSlice 函数中的输入参数为 0 ,时间片轮转调度就不会发生,程序的输出将是:先输出 ITER1* ITER2 个“ task1 ”,再输出 ITER1* ITER2 个“ task2 ”,最后输出 ITER1* ITER2 个“ task3 ”。

6.2优先级抢占调度

如果将例 1 中三个任务的优先级设置的不相同,即将程序改为:
2 :优先级抢占调度
/* includes */
#include "vxWorks.h"
#include "taskLib.h"
#include "kernelLib.h"
#include "sysLib.h"
 
/* function prototypes */
void taskOne(void);
void taskTwo(void);
void taskThree(void);
 
/* globals */
#define ITER1 100
#define ITER2 10
#define HIGH 100 /* high priority */
#define MID 101 /* medium priority */
#define LOW 102 /* low priority */
#define LONG_TIME 0xFFFFFFL
 
void sched(void) /* function to create the two tasks */
{
  int taskIdOne, taskIdTwo, taskIdThree;
 
  printf("\n\n\n\n\n");
  /* spawn the three tasks */
  if ((taskIdOne = taskSpawn("task1", LOW, 0x100, 20000, (FUNCPTR)taskOne, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    printf("taskSpawn taskOne failed\n");
  if ((taskIdTwo = taskSpawn("task2", MID, 0x100, 20000, (FUNCPTR)taskTwo, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    printf("taskSpawn taskTwo failed\n");
  if ((taskIdThree = taskSpawn("task3", HIGH, 0x100, 20000, (FUNCPTR)taskThree,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    printf("taskSpawn taskThree failed\n");
 
}
 
void taskOne(void)
{
…//same with example 1
}
 
void taskTwo(void)
{
…//same with example 1
}
 
void taskThree(void)
{
…//same with example 1
}
再观察程序的运行结果为:先输出 ITER1* ITER2 个“ task3 ”,再输出 ITER1* ITER2 个“ task2 ”,最后输出 ITER1* ITER2 个“ task1 ”。这是因为 task1 task2 task3 的优先级顺序是“ task3 task2 task1 ”,故在 task3 执行完(或被阻塞、挂起)前, task2 得不到执行;同理,在在 task2 执行完(或被阻塞、挂起)前, task1 也得不到执行。

6.3改变任务的优先级

        VxWorks 中,我们可以使用 taskPrioritySet() 函数来动态改变任务的优先级,这个函数的原型是:
STATUS taskPrioritySet (int tid, /* task ID */ int newPriority /* new priority */ );
        我们将例 2 的程序修改,在其中增加 task4 task4 延迟 100 毫秒后,将 task1 的优先级设置到最高:
3 :改变任务的优先级
/* includes */
#include "vxWorks.h"
#include "taskLib.h"
/* function prototypes */
void taskOne(void);
void taskTwo(void);
void taskThree(void);
void taskFour(void);
/* globals */
#define ITER1 100
#define ITER2 1
#define LONG_TIME 1000000
#define HIGH 100 /* high priority */
#define MID 101 /* medium priority */
#define LOW 102 /* low priority */
#define TIMESLICE sysClkRateGet()
 
int taskIdOne, taskIdTwo, taskIdThree;
 
void sched(void) /* function to create the two tasks */
{
  printf("\n\n\n\n\n");
  /* spawn the four tasks */
  if ((taskIdOne = taskSpawn("task1", LOW, 0x100, 20000, (FUNCPTR)taskOne, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    printf("taskSpawn taskOne failed\n");
  if ((taskIdTwo = taskSpawn("task2", MID, 0x100, 20000, (FUNCPTR)taskTwo, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    printf("taskSpawn taskTwo failed\n");
  if ((taskIdThree = taskSpawn("task3", HIGH, 0x100, 20000, (FUNCPTR)taskThree,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    printf("taskSpawn taskThree failed\n");
  if (taskSpawn("task4", HIGH, 0x100, 20000, (FUNCPTR)taskFour, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0) == ERROR)
    printf("taskSpawn taskFour failed\n");
 
}
 
void taskOne(void)
{
…//same with example 1
}
 
void taskTwo(void)
{
…//same with example 1
}
 
void taskThree(void)
{
…//same with example 1
}
 
void taskFour(void)
{
  taskDelay(TIMESLICE / 10);
  taskPrioritySet(taskIdOne, HIGH - 1);
}
        task2 任务运行输出“ task2 ”的过程中, task1 抢占了 task2 CPU 资源,先是输出了所有的“ task1 ”,最后剩余的“ task2 ”得以输出。

       我们用WINDVIEW捕获上述程序中各任务切换的运行轨迹




 本文转自 21cnbao 51CTO博客,原文链接:http://blog.51cto.com/21cnbao/120325,如需转载请自行联系原作者


相关文章
|
3月前
|
安全 Unix Linux
Unix是一个多用户、多任务的操作系统
Unix是一个多用户、多任务的操作系统
232 3
|
3月前
|
边缘计算 人工智能 算法
操作系统的心脏:深入理解任务调度的艺术
在现代计算的宏伟舞台上,操作系统扮演着至高无上的指挥家角色,而任务调度则是其手中那根神奇的指挥棒,它不仅掌控着每一个程序和进程的命运,还确保了整个系统的和谐与高效运行。本文将引领读者踏上一场探索之旅,从基本概念出发,逐步揭示轮转调度、优先级调度等核心策略的神秘面纱,探讨它们如何在不同场景下发挥关键作用。更重要的是,我们将展望下一代调度算法可能带来的创新与变革,以及人工智能如何为这一领域注入新的活力。通过深入浅出的讲解,我们期待每位读者都能从中汲取知识的养分,获得深刻的启发。
73 3
|
2月前
|
存储 iOS开发 MacOS
MacOS环境-手写操作系统-33-多任务多窗口
MacOS环境-手写操作系统-33-多任务多窗口
51 0
|
3月前
|
Web App开发 Linux iOS开发
操作系统的演变:从单任务到多核并发
在数字时代的浪潮中,操作系统作为计算机硬件与应用程序之间的桥梁,其发展历史充满了创新与变革。本文将带领读者穿越时空,探索操作系统如何从简单的单任务处理演化为今天能够高效管理多核处理器的复杂系统。我们将一窥各个时代下操作系统的设计哲学,以及它们是如何影响现代计算的方方面面。加入我们的旅程,一起见证技术的力量如何在每次迭代中重塑世界。
46 7
|
3月前
|
机器学习/深度学习 人工智能 算法
操作系统的未来:从多任务到深度学习的演变之路
本文将探讨操作系统如何从处理简单多任务发展到支持复杂的深度学习任务。我们将分析现代操作系统面临的新挑战,以及它们如何适应人工智能和大数据时代的要求。文章不仅回顾过去,也展望未来,思考操作系统在技术演进中的角色和方向。
68 3
|
3月前
|
人工智能 算法 数据挖掘
操作系统的演变:从单任务到多任务的旅程
操作系统(OS)是计算机系统的核心,它管理硬件资源、提供用户界面并运行应用程序。本文将探讨操作系统如何从单任务环境演变为支持多任务的环境,包括这一过程中的技术挑战和解决方案。我们将看到,随着计算需求的增长,操作系统必须适应更复杂的任务管理和资源分配策略,以提高效率和用户体验。通过这个旅程,我们不仅能够理解操作系统的发展,还能洞察未来可能的趋势。
53 5
|
4月前
|
机器学习/深度学习 人工智能 安全
操作系统的未来:从多任务处理到人工智能
【8月更文挑战第23天】本文将探讨操作系统的发展历程及其未来趋势,特别是人工智能在操作系统中的应用。我们将看到如何通过引入人工智能技术,操作系统能够更加智能化地管理资源,提高系统性能和用户体验。
|
4月前
|
缓存 安全 数据库
探索后端开发的核心原则与实践操作系统的未来:从多任务处理到智能优化
【8月更文挑战第23天】在数字化时代的浪潮中,后端开发作为技术架构的支柱,承载着数据处理、业务逻辑实现和系统性能优化的关键任务。本文将深入探讨后端开发的几大核心原则,包括模块化设计、性能优化、安全性强化及可维护性提升,旨在为读者揭示如何构建一个健壮、高效且安全的后端系统。通过分析这些原则背后的理念及其在实际开发中的应用,本文意在启发读者思考如何在不断变化的技术环境中,持续优化后端开发实践,以适应新的挑战和需求。
|
4月前
|
调度 UED
操作系统中的多任务处理机制
【8月更文挑战第23天】在数字时代,操作系统的核心功能之一是多任务处理。它允许用户同时运行多个程序,优化资源使用,并提高生产效率。本文将深入探讨操作系统如何实现多任务处理,以及这一机制对用户体验和系统性能的影响。通过理解多任务处理的工作原理,用户可以更好地管理计算资源,提升个人和组织的工作效率。
|
4月前
|
人工智能 算法 物联网
操作系统的演变:从单任务到多任务的旅程
【8月更文挑战第20天】在数字时代的浪潮中,操作系统作为计算机系统的核心,经历了从简单的单任务处理到复杂的多任务并行处理的转变。本文将探讨这一转变过程中的关键里程碑,包括早期的批处理系统、多道程序设计的出现、分时系统的创新以及现代操作系统中的多任务处理机制。通过这一旅程,我们将了解操作系统如何适应不断增长的计算需求,并预见未来可能的发展方向。
下一篇
DataWorks