精华内容
下载资源
问答
  • 临界区

    2020-10-19 19:25:52
    临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。 当有线程进入临界区段时,其他线程或是进程必须等待(例如:bounded waiting 等待法)...

    临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。

    当有线程进入临界区段时,其他线程或是进程必须等待(例如:bounded waiting 等待法),有一些同步的机制必须在临界区段的进入点与离开点实现,以确保这些共用资源是被互斥获得使用,例如:semaphore。只能被单一线程访问的设备,例如:打印机。

    展开全文
  • 临界区保护

    2020-03-11 16:33:08
    临界区指的是访问多个任务共享资源的一段代码。当有任务进入临界区时,其它任务必须等待直至该任务离开临界区,以确定共享资源的访问不会冲突。 由于共享资源的访问存在于任务与任务之间、任务与中断I...

    1 临界区保护

    1.1 问题引入

    首先看一下如下问题:
    在这里插入图片描述
    原因分析:

    • 根本原因在于读-改-写过程中随时会被打断,再恢复运行时写,导致打断过程中其它写的效果被覆盖。在这里插入图片描述

    1.2 临界区概念

    临界区的概念如下:

    • 临界区指的是访问多个任务共享资源的一段代码。当有任务进入临界区时,其它任务必须等待直至该任务离开临界区,以确定共享资源的访问不会冲突。
      在这里插入图片描述
      由于共享资源的访问存在于任务与任务之间、任务与中断ISR之间;那么,只需要防止任务在访问共享资源时,切换至其它任务或防止中断发生即可。
      在这里插入图片描述

    1.3 使用关中断保护临界区

    我们可以使用关中断来保护临界区,如下:
    在这里插入图片描述
    但是当中断发生嵌套的时候就会出现问题:
    在这里插入图片描述
    所以我们需要采用如下的解决方案:
    在这里插入图片描述

    1.4 设计实现

    中断控制寄存器PRIMASK:
    在这里插入图片描述
    进入临界区:
    在这里插入图片描述
    退出临界区:
    在这里插入图片描述
    这里只贴一下main.c文件中的内容:

    /*************************************** Copyright (c)******************************************************
    ** File name            :   main.c
    ** Latest modified Date :   2016-06-01
    ** Latest Version       :   0.1
    ** Descriptions         :   主文件,包含应用代码
    **
    **--------------------------------------------------------------------------------------------------------
    ** Created by           :   01课堂 lishutong
    ** Created date         :   2016-06-01
    ** Version              :   1.0
    ** Descriptions         :   The original version
    **
    **--------------------------------------------------------------------------------------------------------
    ** Copyright            :   版权所有,禁止用于商业用途
    ** Author Blog          :   http://ilishutong.com
    **********************************************************************************************************/
    #include "tinyOS.h"
    #include "ARMCM3.h"
    
    // 当前任务:记录当前是哪个任务正在运行
    tTask * currentTask;
    
    // 下一个将即运行的任务:在进行任务切换前,先设置好该值,然后任务切换过程中会从中读取下一任务信息
    tTask * nextTask;
    
    // 空闲任务
    tTask * idleTask;
    
    // 所有任务的指针数组:简单起见,只使用两个任务
    tTask * taskTable[2];
    
    // 用于临界区测试的计数器
    uint32_t tickCounter;
    
    /**********************************************************************************************************
    ** Function name        :   tTaskInit
    ** Descriptions         :   初始化任务结构
    ** parameters           :   task        要初始化的任务结构
    ** parameters           :   entry       任务的入口函数
    ** parameters           :   param       传递给任务的运行参数
    ** Returned value       :   无
    ***********************************************************************************************************/
    void tTaskInit (tTask * task, void (*entry)(void *), void *param, uint32_t * stack)
    {
        // 为了简化代码,tinyOS无论是在启动时切换至第一个任务,还是在运行过程中在不同间任务切换
        // 所执行的操作都是先保存当前任务的运行环境参数(CPU寄存器值)的堆栈中(如果已经运行运行起来的话),然后再
        // 取出从下一个任务的堆栈中取出之前的运行环境参数,然后恢复到CPU寄存器
        // 对于切换至之前从没有运行过的任务,我们为它配置一个“虚假的”保存现场,然后使用该现场恢复。
    
        // 注意以下两点:
        // 1、不需要用到的寄存器,直接填了寄存器号,方便在IDE调试时查看效果;
        // 2、顺序不能变,要结合PendSV_Handler以及CPU对异常的处理流程来理解
        *(--stack) = (unsigned long)(1<<24);                // XPSR, 设置了Thumb模式,恢复到Thumb状态而非ARM状态运行
        *(--stack) = (unsigned long)entry;                  // 程序的入口地址
        *(--stack) = (unsigned long)0x14;                   // R14(LR), 任务不会通过return xxx结束自己,所以未用
        *(--stack) = (unsigned long)0x12;                   // R12, 未用
        *(--stack) = (unsigned long)0x3;                    // R3, 未用
        *(--stack) = (unsigned long)0x2;                    // R2, 未用
        *(--stack) = (unsigned long)0x1;                    // R1, 未用
        *(--stack) = (unsigned long)param;                  // R0 = param, 传给任务的入口函数
        *(--stack) = (unsigned long)0x11;                   // R11, 未用
        *(--stack) = (unsigned long)0x10;                   // R10, 未用
        *(--stack) = (unsigned long)0x9;                    // R9, 未用
        *(--stack) = (unsigned long)0x8;                    // R8, 未用
        *(--stack) = (unsigned long)0x7;                    // R7, 未用
        *(--stack) = (unsigned long)0x6;                    // R6, 未用
        *(--stack) = (unsigned long)0x5;                    // R5, 未用
        *(--stack) = (unsigned long)0x4;                    // R4, 未用
    
        task->stack = stack;                                // 保存最终的值
        task->delayTicks = 0;
    }
    
    /**********************************************************************************************************
    ** Function name        :   tTaskSched
    ** Descriptions         :   任务调度接口。tinyOS通过它来选择下一个具体的任务,然后切换至该任务运行。
    ** parameters           :   无
    ** Returned value       :   无
    ***********************************************************************************************************/
    void tTaskSched () 
    {   
        // 进入临界区,以保护在整个任务调度与切换期间,不会因为发生中断导致currentTask和nextTask可能更改
        uint32_t status = tTaskEnterCritical();
    
        // 空闲任务只有在所有其它任务都不是延时状态时才执行
        // 所以,我们先检查下当前任务是否是空闲任务
        if (currentTask == idleTask) 
        {
            // 如果是的话,那么去执行task1或者task2中的任意一个
            // 当然,如果某个任务还在延时状态,那么就不应该切换到他。
            // 如果所有任务都在延时,那么就继续运行空闲任务,不进行任何切换了
            if (taskTable[0]->delayTicks == 0) 
            {
                nextTask = taskTable[0];
            }           
            else if (taskTable[1]->delayTicks == 0) 
            {
                nextTask = taskTable[1];
            } 
            else 
            {
                tTaskExitCritical(status);
                return;
            }
        } 
        else 
        {
            // 如果是task1或者task2的话,检查下另外一个任务
            // 如果另外的任务不在延时中,就切换到该任务
            // 否则,判断下当前任务是否应该进入延时状态,如果是的话,就切换到空闲任务。否则就不进行任何切换
            if (currentTask == taskTable[0]) 
            {
                if (taskTable[1]->delayTicks == 0) 
                {
                    nextTask = taskTable[1];
                }
                else if (currentTask->delayTicks != 0) 
                {
                    nextTask = idleTask;
                } 
                else 
                {
                    tTaskExitCritical(status);
                    return;
                }
            }
            else if (currentTask == taskTable[1]) 
            {
                if (taskTable[0]->delayTicks == 0) 
                {
                    nextTask = taskTable[0];
                }
                else if (currentTask->delayTicks != 0) 
                {
                    nextTask = idleTask;
                }
                else 
                {
                    tTaskExitCritical(status);
                    return;
                 }
            }
        }
    
        tTaskSwitch();   
    
        // 退出临界区
        tTaskExitCritical(status); 
    }
    
    /**********************************************************************************************************
    ** Function name        :   tTaskSystemTickHandler
    ** Descriptions         :   系统时钟节拍处理。
    ** parameters           :   无
    ** Returned value       :   无
    ***********************************************************************************************************/
    void tTaskSystemTickHandler () 
    {
        // 检查所有任务的delayTicks数,如果不0的话,减1。
        int i;   
        uint32_t status = tTaskEnterCritical();
    
        for (i = 0; i < 2; i++) 
        {
            if (taskTable[i]->delayTicks > 0)
            {
                taskTable[i]->delayTicks--;
            }
        }
        
        // 在中断中也有访问资源
        tickCounter++;
        tTaskExitCritical(status);
    
        // 这个过程中可能有任务延时完毕(delayTicks = 0),进行一次调度。
        tTaskSched();
    }
    
    /**********************************************************************************************************
    ** Function name        :   taskDelay
    ** Descriptions         :   使当前任务进入延时状态。
    ** parameters           :   delay 延时多少个ticks
    ** Returned value       :   无
    ***********************************************************************************************************/
    void taskDelay (uint32_t delay) {
        // 配置好当前要延时的ticks数
        uint32_t status = tTaskEnterCritical();
        currentTask->delayTicks = delay;
        tTaskExitCritical(status);
    
        // 然后进行任务切换,切换至另一个任务,或者空闲任务
        // delayTikcs会在时钟中断中自动减1.当减至0时,会切换回来继续运行。
        tTaskSched();
    }
    
    /*********************************************************************************************************
    ** 系统时钟节拍定时器System Tick配置
    ** 在我们目前的环境(模拟器)中,系统时钟节拍为12MHz
    ** 请务必按照本教程推荐配置,否则systemTick的值就会有变化,需要查看数据手册才了解
    **********************************************************************************************************/
    void tSetSysTickPeriod(uint32_t ms)
    {
      SysTick->LOAD  = ms * SystemCoreClock / 1000 - 1;
      NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
      SysTick->VAL   = 0;
      SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                       SysTick_CTRL_TICKINT_Msk   |
                       SysTick_CTRL_ENABLE_Msk; 
    }
    
    /**********************************************************************************************************
    ** Function name        :   SysTick_Handler
    ** Descriptions         :   SystemTick的中断处理函数。
    ** parameters           :   无
    ** Returned value       :   无
    ***********************************************************************************************************/
    void SysTick_Handler () 
    {
        tTaskSystemTickHandler();
    }
    
    /**********************************************************************************************************
    ** 应用示例
    ** 有两个任务,分别执行task1Entry和task2Entry。功能是分别对相应的变量进行周期性置0置1.
    ** 每个任务都可以占用一段时间的CPU,一旦用完了,就会被强制暂停,切换到另一个任务中去。
    ** 本例中有全局共享的变量criticalCounter,同时在taskDelay和tTaskSystemTickHandler中修改。
    ** 如果不加临界区保护,则在tTaskSystemTickHandler中对criticalCounter的修改将会丢失
    **********************************************************************************************************/
    int task1Flag;
    void task1Entry (void * param) 
    {
        tSetSysTickPeriod(10);
        for (;;) 
        {
            task1Flag = 1;
            taskDelay(1);
            task1Flag = 0;
            taskDelay(1);
        }
    }
    
    int task2Flag;
    void task2Entry (void * param) 
    {
        for (;;) 
        {
            // 临界区演示的计数器
            uint32_t i;
    
            // 由于有临界区的保护,所以即便是这中间中断产生,也不会立即响应中断。
            // criticalCounter的值会被正确修改。等待退出临界区时,才会响应中断,在中断中修改criticalCounter
            // 最终不会导致冲突
    
            // 进入临界区
            uint32_t status = tTaskEnterCritical();
    
            uint32_t counter = tickCounter;
            for (i = 0; i < 0xFFFF; i++) {}         // 故意产生长的延时,以便在此期间发生中断
            tickCounter = counter + 1;
    
            // 退出临界区
            tTaskExitCritical(status);
    
            task2Flag = 1;
            taskDelay(1);
            task2Flag = 0;
            taskDelay(1);
        }
    }
    
    // 任务1和任务2的任务结构,以及用于堆栈空间
    tTask tTask1;
    tTask tTask2;
    tTaskStack task1Env[1024];
    tTaskStack task2Env[1024];
    
    // 用于空闲任务的任务结构和堆栈空间
    tTask tTaskIdle;
    tTaskStack idleTaskEnv[1024];
    
    void idleTaskEntry (void * param) {
        for (;;)
        {
            // 空闲任务什么都不做
        }
    }
    
    int main () 
    {
        // 初始化任务1和任务2结构,传递运行的起始地址,想要给任意参数,以及运行堆栈空间
        tTaskInit(&tTask1, task1Entry, (void *)0x11111111, &task1Env[1024]);
        tTaskInit(&tTask2, task2Entry, (void *)0x22222222, &task2Env[1024]);
        
        // 接着,将任务加入到任务表中
        taskTable[0] = &tTask1;
        taskTable[1] = &tTask2;
    
        // 创建空闲任务
        tTaskInit(&tTaskIdle, idleTaskEntry, (void *)0, &idleTaskEnv[1024]);
        idleTask = &tTaskIdle;
        
        // 我们期望先运行tTask1, 也就是void task1Entry (void * param) 
        nextTask = taskTable[0];
    
        // 切换到nextTask, 这个函数永远不会返回
        tTaskRunFirst();
        return 0;
    }
    
    

    参考资料:

    1. 【李述铜】从0到1自己动手写嵌入式操作系统
    展开全文
  • 临界区指修改临界数据的代码区域。 原子操作指临界区的代码不会被这个临界数据的其他临界区的代码打断。 2、通过一个实例来理解这些概念。 在这个实例中临界数据是标准输出,临界数据对应的其中一个临界区就是...

    1、首先给出这三个名词的定义。

    临界数据指多个进程(或线程)会竞争修改的数据。

    临界区指修改临界数据的代码区域。

    原子操作指临界区的代码不会被这个临界数据的其他临界区的代码打断。

    2、通过一个实例来理解这些概念。

    在这个实例中临界数据是标准输出,临界数据对应的其中一个临界区就是图中红框部分,红框中的临界区代码不应该被其他临界区打断,否则就有可能出现标准输出被打乱。通过信号量使得临界数据同一时间只能被一个临界区访问。

    也就是说如果现在一个临界区在访问这个临界数据,那么当进程进行调度时,绝对不会切换到另一个临界区,只可能切换到其他代码。这也就是上面“同一时间”的含义。

    修改stdout的这一系列操作因为不会被其他临界区打乱,所以变成了原子操作。

    参考:http://blog.csdn.net/ljianhui/article/details/10243617

     

    转载于:https://www.cnblogs.com/midhillzhou/p/7600837.html

    展开全文
  • 怎么理解RTOS临界区

    2020-04-12 14:17:48
    临界资源指的是一次只能一个线程访问共享资源或者是不可中断代码,代码临界区指操作系统在处理时不可分割的代码。一旦这部分代码开始执行,则不允许任何中断打扰。为确保临界段代码的执行,在进入临界段之前要临界...

      临界资源指的是一次只能一个线程访问共享资源或者是不可中断代码,代码临界区指操作系统在处理时不可分割的代码。一旦这部分代码开始执行,则不允许任何中断打扰。为确保临界段代码的执行,在进入临界段之前要临界保护

    临界保护有:禁止线程调度(可响应中断)、关中断(不可相应中断)

    共享资源它可以是具体硬件设备。可以是内存(全局变量或者全局数组缓冲区)、IO、SCI、SPI、flash 等;可以是软件代码比如 printer(str); /* 访问共享打印函数 */

    不可中断代码:硬件初始化、线程创建,不加临界保护可能会被中断打断,硬件初始化失败、线程创建失败 。比如就像上厕所,不可能到了一半就不上了。哈哈哈 有意思吧

      线程创建临界不可中断保护举例

       taskENER_CRITICAL();//进入临界区

       /* 创建线程代码 */
       …

       taskEXIT_CRITICAL();//退出临界区

    保护共享资源经常使用互斥锁,什么是互斥锁???
      互斥锁 mutex 还没有被上锁,那么申请该互斥锁的线程将成功对该互斥锁上锁。如果互斥锁 mutex 已经被当前线程上锁,且互斥锁类型为嵌套锁,则该互斥锁的持有计数加 1,当前线程也不会挂起等待(死锁),但线程必须对应相同次数的解锁。如果互斥锁 mutex 被其他线程上锁持有,则当前线程将被阻塞,一直到其他线程对该互斥锁解锁后,等待该互斥锁的线程将按照先进先出的原则获取互斥锁。

      使用互斥锁会导致一个潜在问题是线程优先级翻转。比如rt_thread 操作系统RTOS 操作系统中实现的是优先级继承算法优先级继承是指提高某个占有某种资源的低优先级线程的优先级,使之与所有等待该资源的线程中优先级最高的那个线程的优先级相等,然后执行,而当这个低优先级线程释放该资源时,优先级重新回到初始设定。因此,继承优先级的线程避免了系统资源被任何中间优先级的线程抢占。

    相关文章:
    18 代码的临界区

    展开全文
  • 线程同步(windows平台):临界区

    千次阅读 2018-10-23 16:42:20
     临界区指的是一个访问共用资源(例:全局变量)的程序片段,该共用资源无法同时被多个线程访问的特性。有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到...
  • 比如有一个ArrayList对象是临界资源 不是你做不到 临界资源其实就是多个线程都会访问的资源临界资源当然不能随便写了 其它的线程仍然可以访问这个资源 然后给它lock了 一个线程要访问它 而是你不可能那么做 但要想...
  • 操作系统学习记录之七:临界区

    千次阅读 2018-08-05 22:32:06
    临界区指并发进程中与互斥共享变量相关的程序段; 多个并发进程访问临界资源时, 存在竞争制约关系;  如果两个进程同时停留在相关的临界区内,就会出现与时间相关的错误; 临界区的描述: 确定临界资源; 确定...
  • 临界段临界区

    2016-08-16 09:58:08
    临界段代码(critical sections),也叫临界区(critical region),是那些必须完整连续运行,不可被打断的代码段。μC/OS-Ⅲ系统中存在大量临界段代码。采用两种方式对临界段代码进行保护:关闭中断、给调度器上锁。...
  • 临界资源 & 临界区

    千次阅读 2016-06-20 08:02:57
    临界资源是每次仅允许一个...一个临界资源可以对应多个临界区(right)显然,若能保证诸进程互斥地进入自己的临界区,便可实现诸进程对临界资源的互斥访问。为此,每个进程在进入临界区之前,应先对欲访问的临界资
  • 临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。当有线程进入临界区段时,其他线程或是进程必须等待(例如:bounded waiting 等待法),...
  • 临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。当有线程进入临界区段时,其他线程或是进程必须等待,有一些同步的机制必须在临界区段的...
  • 临界区管理

    2015-09-18 21:39:28
    1.临界区临界区必须以互斥的方式执行的代码段,也就是说临界区范围内只能由一个活动的线程。例如:修改共享变量的过程中其他的执行线程可能会访问共享变量,那么修改共享变量的代码就被看成是临界区的一部分。...
  • 临界区指的是一个访问共用资源(共用设备或共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。当有线程进入临界区段时,其他线程或是进程必须等待,有一些同步的机制必须在临界区段的进入点与...
  • 临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。 临界区保护方法有四种 (1)第一种方法:直接利用开启或者关闭中断的语句来控制。 比如...
  • 临界代码 与 中断

    2018-06-25 14:06:32
    一、 代码的临界区 代码临界区指操作系统在处理时不可分割的代码。一旦这部分代码开始执行,则不允许任何中断打扰。为确保临界段代码的执行,在进入临界段之前要关中断,而临界段代码执行完以后要立即开中断。如下...
  • 临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。当有线程进入临界区段时,其他线程必须等待(例如:bounded waiting 等待法),有一些...
  • 操作系统 临界资源 临界区

    千次阅读 2019-06-04 13:53:34
    为了保护共享资源,不让多个进程同时访问这个共享资源,即阻止多个进程同时进入访问这些资源的代码段,这个代码段称为临界区(也称为管程),这种一次只允许一个进程访问的资源称为临界资源. 临界资源是每次仅允许一个...
  • 1、临界区  临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。当有线程进入临界区段时,其他线程或是进程必须等待(例如:bounded ...
  • 【STM32】FreeRTOS临界区

    2020-11-08 17:22:01
    临界段代码也叫做临界区,是那些必须完整运行,不能被打断的代码段,比如有的外设的初始化需要严格的时序,初始化过程中不能被打断。FreeRTOS在进入临界端代码的时候需要关闭中断,当处理完临界段代码以后再打开...
  • 简要描述临界资源、临界区及互斥同步机制的原则 答: ①临界资源:每次只允许一个进程访问的资源,分为硬件、软件临界资源。 ②临界区:每个进程中访问临界资源的那段程序,进程对临界区的访问必然相反,每次仅...
  • 临界区模式 Critical Section Pattern 是在一个共享范围中只让一个线程执行的模式.它是所有其它多线程设计模式的基础,所以我首先来介绍它.把着眼点放在范围上,这个模式叫临界区模式,如果把作眼点放在执行的线程上,...
  • 临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。当有线程进入临界区段时,其他线程或是进程必须等待,有一些同步的机制必须在临界区段的...
  • 临界区与互斥量区别

    2019-09-24 01:44:54
    临界区和互斥锁的区别1、临界区只能用于对象在同一进程里线程间的互斥访问;互斥体可以用于对象进程间或线程间的互斥访问...首先明白临界区一段代码,这段代码是用来访问临界资源的。临界资源可以是硬件资源,也...
  • 什么叫临界资源和临界区

    万次阅读 2011-09-29 17:29:10
    临界资源是每次仅允许一个进程访问的资源。 属于临界资源的硬件有打印机、磁带机等,软件有消息缓冲队列、变量、数组、缓冲区等。 诸进程间应采取互斥方式,...显然,若能保证诸进程互斥地进入自己的临界区,便可
  • 多线程程序的临界区

    2019-08-10 16:27:00
    所谓的临界区:是进程中的一段需要访问共享资源并且当另一个进程处于相应代码区域时便不会被执行的代码区域对于临界区的管理的必须要满足一下的四个要求:互斥:同一时间临界区中最多存在一个线程Progress:如是一...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 797
精华内容 318
关键字:

临界区指