zoukankan      html  css  js  c++  java
  • Nucleus PLUS应用系统演示样例

    这个Nucleus PLUS系统应用演示样例包含application_initialization和六个任务,任务在application_initialization中创建。这个演示样例系统体现了Nucleus PLUS的任务调度和运行过程、任务间通信和同步(信号量、事件组)。

    Application_Initialize位于29-70行。演示样例系统的全部系统对象(任务、队列、信号量、事件组)都在该函数中创建。

    在板级初始化程序(INT_ Initialize)结束后,系统開始调用操作系统初始化程序(INC_Initialize),这时须要设置可供用户使用的存储器首地址first_available_memory。本文的演示样例系统中first_available_memory指向一个20000 bytes的内存池,用来分配任务堆栈和队列所用的内存空间,由NU_Create_Memory_Pool创建。Nucleus PLUS的启动过程见:Nucleus PLUS的启动、执行线程和中断处理

    任务定义和任务优先级:

    全部的任务的基本架构都是--完毕一些主要的初始化后開始运行一个无限循环,这个无限循环会等待和处理一些信号、事件或消息。没有不论什么一个发生时则会挂起。

    Application_Initialize创建全部的任务后。INC_Initialize会调用TCT_schedule開始调度。

    TCT_schedule会依照任务优先级顺序调度全部的任务去完毕各个任务主要的初始化。然后进入就绪或挂起状态。最后TCT_schedule会将控制权交给优先级最高的任务,本演示样例系统中任务0将是第一个运行的任务。

    Nucleus PLUS的任务优先级从0-255。当中0优先级最高。高优先级的任务可以抢占低优先级的任务。同等优先级的任务依照创建和进入就绪状态的顺序调度运行。

    演示样例系统中的六个任务中task0优先级最高,为优先级1,所以系统開始执行时第一个被执行。任务3、4的优先级是5。任务0挂起后,任务3会执行。任务3挂起则任务4開始执行。之所以任务3先于任务4执行是由于任务3先被创建和调度。Nucleus plus的调度算法是时间片和robin算法,同一优先级的任务依照其进入就绪状态的顺序进行。任务5的优先级是7,任务4挂起后执行。

    任务1和2的优先级是10,任务5挂起后执行任务1,任务1由于队列满而挂起时任务2执行。

    任务0(行71-91):任务0的死循环里会连续的调用函数NU_Sleep和NU_Set_Events。因为NU_Sleep的调用,任务0每18个时钟节拍才可以执行1次。NU_Set_Events设定的event flag在任务5中使用,每一次NU_Set_Events的调用都会使任务5进入就绪状态

    任务1(行92-119):任务1会持续的向队列0发送单个32-bit的message,知道队列0满就会挂起。队列有空间时就被唤醒。因为任务1、2具有同样的优先级,任务1先被创建,所以任务1挂起后任务2才干恢复运行。恢复运行指的是进入就绪状态等待CPU调度,当然高优先级的任务会抢占CPU,迫使低优先级的任务挂起。

    任务2(行120-155):任务2 会持续的从队列0中读取消息。每次读取单个32-bit的消息。

    当队列为空时任务2挂起,任务1恢复运行。

    由于任务1、2具有同样的优先级,谁也不能抢占谁,所以仅仅能当中一个被挂起后还有一个才干恢复执行,所以即使队列0有可用空间/有可用消息,任务1/任务2也不能马上恢复执行。

    任务3、4(行156-183):任务3、4具有同样的指令代码,可是每一个任务有独立的任务堆栈。这两个任务竞争一个二元信号量,每当一个任务竞争到该信号量时就会睡眠100个时钟节拍,然是释放该信号量。没有竞争到的任务则会挂起,等待再次竞争该信号量。每次信号量释放后,等待该信号量的任务挂起状态都被中止(即任务再次竞争该信号量)。

    任务5(行184-end):任务5是一个等待某event的发生(即某event flag被设置)的无限循环,该event flag在任务0中被设置(NU_Set_Events)。

    所以任务5和任务0执行的频率是同样的。

    程序源代码例如以下(源自Nucleus PLUS reference):

     /* Include necessary Nucleus PLUS files. */  
     #include “nucleus.h”   
     /* Define Application data structures. */  
     NU_TASK Task_0;   
     NU_TASK Task_1;   
     NU_TASK Task_2;   
     NU_TASK Task_3;   
     NU_TASK Task_4;   
     NU_TASK Task_5;   
     NU_QUEUE Queue_0;   
     NU_SEMAPHORE Semaphore_0;   
     NU_EVENT_GROUP Event_Group_0;   
     NU_MEMORY_POOL System_Memory;   
     /* Allocate global counters. */  
     UNSIGNED Task_Time;   
     UNSIGNED Task_2_messages_received;   
     UNSIGNED Task_2_invalid_messages;   
     UNSIGNED Task_1_messages_sent;   
     NU_TASK *Who_has_the_resource;   
     UNSIGNED Event_Detections;   
     /* Define prototypes for function references. */  
     void task_0(UNSIGNED argc, VOID *argv);   
     void task_1(UNSIGNED argc, VOID *argv);   
     void task_2(UNSIGNED argc, VOID *argv);   
     void task_3_and_4(UNSIGNED argc, VOID *argv);   
     void task_5(UNSIGNED argc, VOID *argv);   
     /* Define the Application_Initialize routine that determines the initial  
     Nucleus PLUS application environment. */  
     void Application_Initialize(void *first_available_memory)   
     {   
     VOID *pointer;   
     /* Create a system memory pool that will be used to allocate task  
     stacks, queue areas, etc. */  
     NU_Create_Memory_Pool(&System_Memory, “SYSMEM”, first_available_memory,   
     20000, 50, NU_FIFO);   
     /* Create each task in the system. */  
     /* Create task 0. */  
     NU_Allocate_Memory(&System_Memory, &pointer, 1000, NU_NO_SUSPEND);   
     NU_Create_Task(&Task_0, “TASK 0”, task_0, 0, NU_NULL, pointer, 1000, 1,   
     20, NU_PREEMPT, NU_START);   
     /* Create task 1. */  
     NU_Allocate_Memory(&System_Memory, &pointer, 1000, NU_NO_SUSPEND);   
     NU_Create_Task(&Task_1, “TASK 1”, task_1, 0, NU_NULL, pointer, 1000, 10,   
     5,NU_PREEMPT, NU_START);   
     /* Create task 2. */  
     NU_Allocate_Memory(&System_Memory, &pointer, 1000, NU_NO_SUSPEND);   
     NU_Create_Task(&Task_2, “TASK 2”, task_2, 0, NU_NULL, pointer, 1000,   
     10, 5, NU_PREEMPT, NU_START);   
     /* Create task 3. Note that task 4 uses the same instruction area. */  
     NU_Allocate_Memory(&System_Memory, &pointer, 1000, NU_NO_SUSPEND);   
     NU_Create_Task(&Task_3, “TASK 3”, task_3_and_4, 0, NU_NULL, pointer,   
     1000, 5, 0, NU_PREEMPT, NU_START);   
     /* Create task 4. Note that task 3 uses the same instruction area.*/  
     NU_Allocate_Memory(&System_Memory, &pointer, 1000, NU_NO_SUSPEND);   
     NU_Create_Task(&Task_4, “TASK 4”, task_3_and_4, 0, NU_NULL, pointer,   
     1000, 5, 0, NU_PREEMPT, NU_START);   
     /* Create task 5. */  
     NU_Allocate_Memory(&System_Memory, &pointer, 1000, NU_NO_SUSPEND);   
     NU_Create_Task(&Task_5, “TASK 5”, task_5, 0, NU_NULL, pointer, 1000, 7, 0,   
     NU_PREEMPT, NU_START);   
     /* Create communication queue. */  
     NU_Allocate_Memory(&System_Memory, &pointer, 100*sizeof(UNSIGNED),   
     NU_NO_SUSPEND);   
     NU_Create_Queue(&Queue_0, “QUEUE 0”, pointer, 100, NU_FIXED_SIZE, 1,   
     NU_FIFO);   
     /* Create synchronization semaphore. */  
     NU_Create_Semaphore(&Semaphore_0, “SEM 0”, 1, NU_FIFO);   
     /* Create event flag group. */  
     NU_Create_Event_Group(&Event_Group_0, “EVGROUP0”);   
     }   
     /* Define task 0. Task 0 increments the Task_Time variable every  
     18 clock ticks. Additionally, task 0 sets an event flag that  
     task 5 is waiting for, on each iteration of the loop. */  
     void task_0(UNSIGNED argc, VOID *argv)   
     {   
     STATUS status;   
     /* Access argc and argv just to avoid compilation warnings.*/  
     status = (STATUS) argc + (STATUS) argv;   
     /* Set the clock to 0. This clock ticks every 18 system timer ticks. */  
     Task_Time = 0;   
     while(1)   
     {   
     /* Sleep for 18 timer ticks. The value of the tick is programmable in  
    IND.ASM and is relative to the speed of the target system. */  
     NU_Sleep(18);   
     /* Increment the time. */  
     Task_Time++;   
     /* Set an event flag to lift the suspension on task 5.*/  
     NU_Set_Events(&Event_Group_0, 1, NU_OR);   
     }   
     }   
     /* Define the queue sending task. Note that the only things that cause  
     this task to suspend are queue full conditions and the time slice  
     specified in the configuration file. */  
     void task_1(UNSIGNED argc, VOID *argv)   
     {   
     STATUS status;   
     UNSIGNED Send_Message;   
     /* Access argc and argv just to avoid compilation warnings. */  
     status = (STATUS) argc + (STATUS) argv;   
     /* Initialize the message counter. */  
     Task_1_messages_sent = 0;   
     /* Initialize the message contents. The receiver will  
     examine the message contents for errors. */  
     Send_Message = 0;   
     while(1)   
     {   
     /* Send the message to Queue_0, which task 2 reads from. Note  
     that if the destination queue fills up this task suspends until  
     room becomes available. */  
     status = NU_Send_To_Queue(&Queue_0, &Send_Message, 1,   
     NU_SUSPEND);   
     /* Determine if the message was sent successfully. */  
     if (status == NU_SUCCESS)   
     Task_1_messages_sent++;   
     /* Modify the contents of the next message to send. */  
     Send_Message++;   
     }   
     }   
     /* Define the queue receiving task. Note that the only things that  
     cause this task to suspend are queue empty conditions and the  
     time slice specified in the configuration file. */  
     void task_2(UNSIGNED argc, VOID *argv)   
     {   
     STATUS status;   
     UNSIGNED Receive_Message;   
     UNSIGNED received_size;   
     UNSIGNED message_expected;   
     /* Access argc and argv just to avoid compilation warnings. */  
     status = (STATUS) argc + (STATUS) argv;   
     /* Initialize the message counter. */  
     Task_2_messages_received = 0;   
     /* Initialize the message error counter. */  
     Task_2_invalid_messages = 0;   
     /* Initialize the message contents to expect. */  
     message_expected = 0;   
     while(1)   
     {   
     /* Retrieve a message from Queue_0, which task 1 writes to.  
     Note that if the source queue is empty this task  
     suspends until something becomes available. */  
     status = NU_Receive_From_Queue(&Queue_0, &Receive_Message, 1,   
     &received_size, NU_SUSPEND);   
     /* Determine if the message was received successfully. */  
     if (status == NU_SUCCESS)   
     Task_2_messages_received++;   
     /* Check the contents of the message against what this task  
     is expecting. */  
     if ((received_size != 1) ||   
     (Receive_Message != message_expected))   
     Task_2_invalid_messages++;   
     /* Modify the expected contents of the next message. */  
     message_expected++;   
     }   
     }   
     /* Tasks 3 and 4 want a single resource. Once one of the tasks gets the  
     resource, it keeps it for 30 clock ticks before releasing it. During  
     this time the other task suspends waiting for the resource. Note that  
     both task 3 and 4 use the same instruction areas but have different  
     stacks. */  
     void task_3_and_4(UNSIGNED argc, VOID *argv)   
     {   
     STATUS status;   
     /* Access argc and argv just to avoid compilation warnings. */  
     status = (STATUS) argc + (STATUS) argv;   
     /* Loop to allocate and deallocate the resource. */  
     while(1)   
     {   
     /* Allocate the resource. Suspend until it becomes available. */  
     status = NU_Obtain_Semaphore(&Semaphore_0, NU_SUSPEND);   
     /* If the status is successful, show that this task owns the  
     resource. */  
     if (status == NU_SUCCESS)   
     {   
     Who_has_the_resource = NU_Current_Task_Pointer();   
     /* Sleep for 100 ticks to cause the other task to suspend on  
     the resource. */  
     NU_Sleep(100);   
    /* Release the semaphore. */  
     NU_Release_Semaphore(&Semaphore_0);   
     }   
     }   
     }   
     /* Define the task that waits for the event to be set by task 0. */  
     void task_5(UNSIGNED argc, VOID *argv)   
     {   
     STATUS status;   
     UNSIGNED event_group;   
     /* Access argc and argv just to avoid compilation warnings. */  
     status = (STATUS) argc + (STATUS) argv;   
     /* Initialize the event detection counter. */  
     Event_Detections = 0;   
     /* Continue this process forever. */  
     while(1)   
     {   
     /* Wait for an event and consume it. */  
     status = NU_Retrieve_Events(&Event_Group_0, 1, NU_OR_CONSUME,   
     &event_group, NU_SUSPEND);   
     /* If the status is okay, increment the counter. */  
     if (status == NU_SUCCESS)   
     Event_Detections++;   
     }   
     }  

  • 相关阅读:
    C#访问MySql连接字符串
    简单的async和await用法
    Nuget新旧地址更换
    【NPS】nps分多少算好
    「干货」什么Linux是邮件服务器?
    「干货」编程语言十大经典算法,你知道几个?
    实验干货分享:用Go语言实现分布式缓存开发之map
    开发微信小程序游戏真的有手就行吗?
    图数据库Neo4j的介绍与使用
    干货分享:什么是Java设计三大工厂模式?
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/7044525.html
Copyright © 2011-2022 走看看