精华内容
下载资源
问答
  • 2016-07-07 LT 互斥型信号量管理 任务可以用互斥型信号量实现对共享资源的独占处理。...与信号量管理区别不大。 实现优先级天花板协议。(OSEventCnt分为两部分,一部分存当前任务的优先级,另一部分存天花板优先级)

    2016-07-07 LT

    互斥型信号量管理

    1. 任务可以用互斥型信号量实现对共享资源的独占处理。
    2. 与信号量管理区别不大。
    3. 实现优先级天花板协议。(OSEventCnt分为两部分,一部分存当前任务的优先级,另一部分存天花板优先级)

    8.00 建立一个互斥信号量,OSMutexCreate()

    8.01 删除一个互斥型信号量,OSMutexDel()

    8.02 等待一个互斥型信号量(挂起),OSMutexPend()

    8.03 释放一个互斥型信号量,OSMutexPost()

    8.04 无等待地获取一个互斥型信号量,OSMutexAccept()

    8.05 获取信号量当前状态,OSMutexQuery()

    展开全文
  • 信号量与互斥量的区别

    千次阅读 2017-04-02 12:46:53
    多任务间同步的方式包括关中断,调度器上锁, 互斥量(mutex),信号量,消息队列几种, 其中互斥量和信号量使用使用方式相近,连概念和实现都有些近似, 所以没有扎实操作系统背景知识的同学常常分不清出他们的区别,...

    多任务间同步的方式包括关中断,调度器上锁, 互斥量(mutex),信号量,消息队列几种, 其中互斥量和信号量使用使用方式相近,连概念和实现都有些近似, 所以没有扎实操作系统背景知识的同学常常分不清出他们的区别,容易混淆, 下面简单分析以下.

    1.互斥量

        互相斥量是管理临界资源的一种有效手段, 因为互斥量是独占的, 所以在一个时刻只允许一个线程占有互斥量,利用这个性质来实现共享资源的互斥量保护,任何时刻只允许一个线程获得互斥量对象,未能够获得互斥量对象的线程被挂起在该互斥量的等待线程队列上,这一点和1资源信号量是相同的, 但互斥量有所有者的概念,高优先级的任务可以在获取互斥量时通过对比所有者的优先级是否高于自己来决定是否提升所有者的优先级。  所以互斥量可以有效对付优先级反转的问题。

    2.信号量

     信号量是用来解决线程同步和互斥的通用工具, 和互斥量类似, 信号量也可以用作自于资源互斥访问, 但信号量没有所有者的概念,在应用上比互斥量更广泛,信号量比较简单, 不能解决优先级反转问题,但信号量是一种轻量级的对象,比互斥量小巧,灵活,因此在很多对互斥要求不严格的的系统中,经常使用信号量来管理互斥资源。

    小结:

      关于所有者的概念,最开始我也不是很清楚它的内涵,最近看了一下FreeRTOS 信号量头文件的一些注释,有些感悟和收获,注释原文在 freertoscode/source/include/semphr.h中。 

     * This type of semaphore can be used for pure synchronisation between tasks or
     * between an interrupt and a task.  The semaphore need not be given back once
     * obtained, so one task/interrupt can continuously 'give' the semaphore while
     * another continuously 'takes' the semaphore.  For this reason this type of
     * semaphore does not use a priority inheritance mechanism.
     For an alternative
     * that does use priority inheritance see xSemaphoreCreateMutex().
     *

    大概意思是说, sem和mutex的使用方式不同, 对于同一个上下文内来说,mutex的获取和释放必须成对调用, 获取次数和释放次数必须一样,强调所有权的概念。

    sem则没有这些限制,可以一个上下文执行释放,另一个上下文执行获取, 强调的是资源数的概念,至于资源是谁发出的,没有限制,同等对待,获取了不去释放,也无关紧要,反正不获取也能发出,资源可以无中生有.

    总结成一句话就是:sem可以“无中生有",但是mutex不可以。

    结束!


     

    展开全文
  • 在上一讲中奔腾的心:FreeRTOS 从入门到精通9--中断管理​zhuanlan.zhihu.com我们探讨了中断管理在FreeRTOS中的概念和应用,在本讲中我们将讨论FreeRTOS一个十分重要的话题--资源管理(Resource Management),并借此...

    在上一讲中奔腾的心:FreeRTOS 从入门到精通9--中断管理​zhuanlan.zhihu.com

    我们探讨了中断管理在FreeRTOS中的概念和应用,在本讲中我们将讨论FreeRTOS一个十分重要的话题--资源管理(Resource Management),并借此介绍一个值得嵌入式开发者重视的现象--优先级倒置(Priority inversion )。本个系列教程也将完结于此,很高兴读者能一路支持过来并希望能有所收获。其实通过这十讲离真正的精通还是有不少差距的,应该能起到入门及抛砖引玉的作用,而我又不小心当了回标题党。感叹完毕,让我们言归正传。

    什么是资源管理

    资源管理(Resource Management)顾名思义,就是对资源的管理。资源在FreeRTOS中可以表现为一个负责保存数据的全局变量,一个队列上的数据等需要在任务之间共享的数据或者对UART串口的操作资源等。

    资源管理主要包括两个方面内容--数据的同步机制和资源的保护机制。

    数据的同步与信号量

    数据的同步是指,如何能通知任务新数据的到来并同时提高CPU的利用率。假设一个简单的生产者消费者模型--有两个任务,一个任务是数据的生产者(Producer)任务,一个任务是数据的消费者(Consumer)任务,消费者任务等待生产者任务产生的数据并进行处理。按照正常的思路,消费者任务和生产者任务会轮流执行,但是如果在消费者任务执行的时候数据还没有产生的话,消费者任务的运行就是无用的,会降低CPU的使用效率。为此,FreeRTOS引入了信号量(Semaphore)概念,通过信号量的同步机制可以使消费者任务在数据还没到达的时候进入阻塞状态,并让出CPU资源给其他任务。信号量是一种同步机制,可以起到消息通知和提高CPU利用率的作用。对于信号量的操作有两种,获取信号量(taking a semaphore)和给予信号量(giving a semaphore)。在生产者消费者模型中,生产者生产数据后给予信号量,消费者获取信号量后可以处理数据。信号量又分为二进制信号量(binary semaphore)和计数信号量(counting semaphore)。二进制信号量中信号量的数目最多为1,即最多只能通知解锁一个任务;多元信号量信号量的数目可以自定义设定,可以通知解锁多个任务。

    通常可以把二进制信号量(binary semaphore)类比成含有一个“钥匙”的队列,计数信号量(counting semaphore)可以类比成含有多个“钥匙”的队列。

    下面介绍下信号量相关的系统API函数

    SemaphoreHandle_t xSemaphoreCreateBinary( void )

    通过xSemaphoreCreateBinary()函数可以创建一个二进制信号量,如果返回值是NULL的话表示创建信号量失败(通常是因为没有足够可用的堆内存)。如果返回值非空的话表示创建成功,返回值即为所创建信号量的具柄。

    BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait )

    xSemaphoreTake()函数表示获取信号量,函数的参数如下xSemaphore 信号量的句柄

    xTicksToWait 如果信号量不可用的话任务处于阻塞状态的最长时间,设置为 portMAX_DELAY的话任务会一直处于阻塞状态直到信号量可用,设置为0的话如果信号量不可用的话会直接返回

    函数的返回值为pdPASS表示成功获取了信号量,返回值为pdFALSE表示获取信号量失败

    BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

    xSemaphoreGive()函数表示给予信号量,函数的参数如下xSemaphore 信号量的句柄

    函数的返回值为pdPASS表示成功给予信号量,返回值为pdFALSE表示给予信号量失败

    在中断函数中应该使用如下版本

    BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,

    BaseType_t *pxHigherPriorityTaskWoken )

    二进制信号量的应用伪代码

    首先申明个信号量的全局变量

    SemaphoreHandle_t xBinarySemaphore;

    然后在main函数中创建信号量

    int main(void)

    {

    ...

    xBinarySemaphore = xSemaphoreCreateBinary();

    ...

    }

    void Task_Producer(void const * argument)

    {

    //生产者任务负责生产数据并给予信号量 for( ;; )

    {

    ...

    if(true==produce_some_data())

    {

    xSemaphoreGive(xBinarySemaphore);

    }

    ...

    }

    }

    void Task_Consumer(void const * argument)

    {

    //消费者任务等待获取信号量并进行数据处理 for( ;; )

    {

    xSemaphoreTake( xBinarySemaphore, portMAX_DELAY );

    //下面是对数据的处理函数 ...

    }

    }

    二进制信号量适用于在数据产生的频率比较低的场合。如果数据产生的频率较高,因为信号量最多只能保存一个信号,更多产生的数据将会直接被忽略抛弃。对此,我们需要使用计数信号量(counting semaphore)。

    计数信号量相关的函数如下

    SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount,

    UBaseType_t uxInitialCount );

    xSemaphoreCreateCounting()用于创建计数信号量,函数的参数如下uxMaxCount计数信号量包含信号量的最大值

    uxInitialCount 计数信号量中信号量的初始值

    计数信号量创建好对信号量的操作函数和二进制信号量一样,所以应用代码参照二进制信号量

    资源的保护与互斥量

    资源的保护是指,如何保护资源不被多个任务同时操作。如果一个保存数据的全局变量在被一个任务操作的过程中,又被多个更高优先级的任务抢占并处理,那么最后这个支离破碎的数据将会毫无意义,破坏了数据的独立完整性;如果一个任务在使用uart串口发送数据的时候,又被多个更高优先级的任务抢占串口资源并发送数据,那么最后串口发送的数据将只是一堆乱码毫无意义,造成了系统的不稳定性。

    在一定程度上,使用上文介绍的信号量不仅可以同步数据,也可以起到资源保护的作用。信号量用于资源保护的作用

    在上图中,有个低优先级的任务(LP)和高优先级的任务(HP),两个任务都可以对一个资源进行操作。为了对资源进行保护采用了信号量的机制。LP首先获得信号量可以对资源进行操作,在时刻1,HP因为优先级高在内核调度中抢占了LP,在时刻2,HP想获得信号量但失败因此进入了阻塞状态。之后LP可以继续对资源操作,在时刻3执行完毕后归还了信号量。在时刻4,HP因为优先级高在内核调度中抢占了LP并获取了信号量可以对资源可以操作。

    在上面这个示例中,不同优先级的任务采用信号量机制可以独立地使用资源并不会被打断,因此保护了资源。但采用信号量保护资源的话会有个弊端,有时会产生一种现象叫做优先级倒置(Priority inversion )。下图将介绍这个现象。优先级倒置

    这个示例和上图示例基本相同,就是多了一个优先级介于LP和HP之间的任务(MP),问题发生在时刻3。此时低优先级的任务获得了信号量和对资源的操作权,但被优先级更高的MP抢占了并执行。最高优先级的任务HP等待低优先级任务LP返还信号量,而低优先级因为被中等优先级的任务MD抢占无法返回信号量。从外部的视角看,此时中等优先级的任务MD相当于抢占了高优先级的任务HP,而高优先级的任务HP表现起来却又像是有最低的优先级。这种不正常的现象就被称为优先级倒置。优先级倒置是采用信号量保护资源可能会产生的负面效果。

    FreeRTOS为了解决资源保护的问题引入了互斥量(Mutex)。互斥量又是何方神圣,如何解决优先级倒置的问题呢?

    互斥量是二进制信号量的一个变种,开启互斥量需要在头文件FreeRTOSConfig.h设置configUSE_MUTEXES 为1。互斥量和信号量的主要区别如下互斥量用于保护资源时必须要被返还

    信号量用于数据同步时不需要返还

    互斥量操作的相关函数

    SemaphoreHandle_t xSemaphoreCreateMutex( void )

    xSemaphoreCreateMutex()函数用于创建互斥量

    互斥量的应用伪代码

    首先申明个互斥量的全局变量

    SemaphoreHandle_t xMutex;

    然后在main函数中创建互斥量

    int main(void)

    {

    ...

    xMutex = xSemaphoreCreateMutex();

    ...

    }

    void Function_Resource(void const * argument)

    {

    //要保护的资源函数 ...

    xSemaphoreTake( xMutex, portMAX_DELAY );

    {

    //对资源的处理 ...

    }

    xSemaphoreGive( xMutex );

    ...

    }

    在上段代码中,如果有多个任务要调用资源函数的话,通过资源函数内部的互斥量机制可以保护资源不被其他任务打断。关于互斥量如何解决优先级倒置的问题,FreeRTOS为互斥量赋予了优先级继承(priority inheritance)的特性。优先级继承会暂时提高获得互斥量的任务的优先级,使得含有互斥量的任务的优先级和想要获取互斥量的任务中的最高优先级一样。互斥量无法彻底避免优先级倒置的问题,但能显著降低事情发生的概率。

    关于资源保护的另一种方法--关键区(Critical Section)

    在FreeRTOS有两个宏定义,分别是taskENTER_CRITICAL()和taskEXIT_CRITICAL()。

    代码如下

    taskENTER_CRITICAL();

    ...

    taskEXIT_CRITICAL();

    taskENTER_CRITICAL()宏定义会关闭所有中断包括内核切换所在的中断,taskEXIT_CRITICAL()宏定义会再次打开中断。所以处于宏定义之间的代码可以被独占地执行,这是保护资源的一种比较暴力的方式。

    这个FreeRTOS的教程系列基本上到此完结了,如果你对这个系列有什么想法感受或者建议的话欢迎发表评论。之后我会考虑是否写一些FreeRTOS的实战应用教程。

    展开全文
  • uC/OS-III之资源管理--互斥信号量

    千次阅读 2017-06-02 17:37:37
    1.uC/OS-III支持一种特殊的二进制信号量–互斥型信号量。2.互斥型信号量通过安全优先级继承机制(一旦一个具有高优先级的任务H想要...注:与信号量一样,只有任务才能使用互斥型信号量(中断服务程序不可以)。typed

    1.uC/OS-III支持一种特殊的二进制信号量–互斥型信号量。

    2.互斥型信号量通过安全优先级继承机制(一旦一个具有高优先级的任务H想要访问共享资源,占有该资源的任务的优先级将被提升至与任务H一样),来避免无界优先级翻转的问题。

    3.互斥型信号量是一种被定义为OS_MUTEX数据类型的内核对象,它的定义位于os.h中。
    注:与信号量一样,只有任务才能使用互斥型信号量(中断服务程序不可以)。

    typedef  struct  os_mutex            OS_MUTEX;              // 625行
    
    struct  os_mutex {                                          // 817行 - 830行
        OS_OBJ_TYPE          Type;                              // 互斥信号量的类型,必须设置成OS_OBJ_TYPE_MUTEX
        CPU_CHAR            *NamePtr;                           // 互斥信号量的名称
        OS_PEND_LIST         PendList;                          // 任务挂起表
    #if OS_CFG_DBG_EN > 0u                                      // 调试相关
        OS_MUTEX            *DbgPrevPtr;
        OS_MUTEX            *DbgNextPtr;
        CPU_CHAR            *DbgNamePtr;
    #endif
        OS_TCB              *OwnerTCBPtr;                       // 指向占有该互斥信号量的任务的任务控制块OS_TCB
        OS_PRIO              OwnerOriginalPrio;                 // 记录任务占有互斥信号量之前的优先级
        OS_NESTING_CTR       OwnerNestingCtr;                   // 互斥信号量的嵌套深度
        CPU_TS               TS;                                // 记录上一次被释放的时间
    };

    4.互斥型信号量通过OSMutexCreate()创建,它的定义位于os_mutex.c中。

    void  OSMutexCreate (OS_MUTEX    *p_mutex,
                         CPU_CHAR    *p_name,
                         OS_ERR      *p_err)                    // 66行 - 118行
    {
        CPU_SR_ALLOC();                                         // 声明变量cpu_sr,用来临时存储CPU的状态寄存器
    
    #ifdef OS_SAFETY_CRITICAL                                   // 系统安全性检查
        if (p_err == (OS_ERR *)0) {
            OS_SAFETY_CRITICAL_EXCEPTION();
            return;
        }
    #endif
    
    #ifdef OS_SAFETY_CRITICAL_IEC61508                          // 系统安全性检查(IEC61508)
        if (OSSafetyCriticalStartFlag == DEF_TRUE) {
           *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
            return;
        }
    #endif
    
    #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u                      // 允许进行ISR调用检查
        if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              // 不允许在ISR中调用
            *p_err = OS_ERR_CREATE_ISR;
            return;
        }
    #endif
    
    #if OS_CFG_ARG_CHK_EN > 0u                                  // 允许参数检查
        if (p_mutex == (OS_MUTEX *)0) {                         // 无效参数
            *p_err = OS_ERR_OBJ_PTR_NULL;
            return;
        }
    #endif
    
        CPU_CRITICAL_ENTER();                                   // 进入临界区
        p_mutex->Type              =  OS_OBJ_TYPE_MUTEX;        // 标记结构体为互斥型信号量
        p_mutex->NamePtr           =  p_name;
        p_mutex->OwnerTCBPtr       = (OS_TCB       *)0;
        p_mutex->OwnerNestingCtr   = (OS_NESTING_CTR)0;         // 当OwnerNestingCtr为0时,互斥信号量可用
        p_mutex->TS                = (CPU_TS        )0;
        p_mutex->OwnerOriginalPrio =  OS_CFG_PRIO_MAX;
        OS_PendListInit(&p_mutex->PendList);                    // 初始化挂起表
    
    #if OS_CFG_DBG_EN > 0u
        OS_MutexDbgListAdd(p_mutex);
    #endif
        OSMutexQty++;                                           // 系统互斥信号量数目加1
    
        CPU_CRITICAL_EXIT();                                    // 退出临界区
        *p_err = OS_ERR_NONE;
    }

    5.等待互斥信号量使用OSMutexPend(),它的定义位于os_mutex.c中。

    void  OSMutexPend (OS_MUTEX   *p_mutex,
                       OS_TICK     timeout,
                       OS_OPT      opt,
                       CPU_TS     *p_ts,
                       OS_ERR     *p_err)                         // 329行 - 493行
    {
        OS_PEND_DATA  pend_data;
        OS_TCB       *p_tcb;
        CPU_SR_ALLOC();                                           // 声明变量cpu_sr,用来临时存储CPU的状态寄存器
    
    #ifdef OS_SAFETY_CRITICAL                                   // 系统安全性检查
        if (p_err == (OS_ERR *)0) {
            OS_SAFETY_CRITICAL_EXCEPTION();
            return;
        }
    #endif
    
    #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u                      // 允许进行ISR调用检查
        if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              // 不允许在ISR中调用该函数
           *p_err = OS_ERR_PEND_ISR;
            return;
        }
    #endif
    
    #if OS_CFG_ARG_CHK_EN > 0u                                  // 允许进行参数检查
        if (p_mutex == (OS_MUTEX *)0) {                         // 无效的参数
            *p_err = OS_ERR_OBJ_PTR_NULL;
            return;
        }
        switch (opt) {
            case OS_OPT_PEND_BLOCKING:
            case OS_OPT_PEND_NON_BLOCKING:
                 break;
            default:                                            // 无效的选项
                 *p_err = OS_ERR_OPT_INVALID;
                 return;
        }
    #endif
    
    #if OS_CFG_OBJ_TYPE_CHK_EN > 0u                             // 允许进行类型检查
        if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) {               // 确保互斥型已被创建
            *p_err = OS_ERR_OBJ_TYPE;
            return;
        }
    #endif
    
        if (p_ts != (CPU_TS *)0) {
           *p_ts  = (CPU_TS  )0;                                // 初始化返回的时间戳参数
        }
    
        CPU_CRITICAL_ENTER();                                   // 进入临界区
        if (p_mutex->OwnerNestingCtr == (OS_NESTING_CTR)0) {    // 嵌套层数OwnerNestingCtr为0时,表示互斥信号量可用
            p_mutex->OwnerTCBPtr       =  OSTCBCurPtr;
            p_mutex->OwnerOriginalPrio =  OSTCBCurPtr->Prio;
            p_mutex->OwnerNestingCtr   = (OS_NESTING_CTR)1;
            if (p_ts != (CPU_TS *)0) {
               *p_ts                   = p_mutex->TS;           // 返回上次释放互斥信号量的时间
            }
            CPU_CRITICAL_EXIT();                                // 退出临界区
            *p_err                     =  OS_ERR_NONE;
            return;
        }
                                                                // 互斥信号量不可用
        if (OSTCBCurPtr == p_mutex->OwnerTCBPtr) {              // 当前任务正在使用互斥信号量
            p_mutex->OwnerNestingCtr++;                         // 嵌套层数加1
            if (p_ts != (CPU_TS *)0) {
               *p_ts  = p_mutex->TS;
            }
            CPU_CRITICAL_EXIT();                                // 退出临界区
            *p_err = OS_ERR_MUTEX_OWNER;                        // 说明一下当前任务已拥有该互斥信号量
            return;
        }
    
        if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {    // 非阻塞型
            CPU_CRITICAL_EXIT();                                // 退出临界区
            *p_err = OS_ERR_PEND_WOULD_BLOCK;
            return;
        } else {                                                // 阻塞型
            if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {    // 调度器是锁定
                CPU_CRITICAL_EXIT();                            // 退出临界区
                *p_err = OS_ERR_SCHED_LOCKED;
                return;
            }
        }
                                                                // 阻塞型
        OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();                  // 进入临界区,使能中断
        p_tcb = p_mutex->OwnerTCBPtr;                           // 执行占有该互斥信号量的任务的任务控制块OS_TCB
        if (p_tcb->Prio > OSTCBCurPtr->Prio) {                  // 拥有互斥信号量的任务的优先级低于当前任务的优先级
            switch (p_tcb->TaskState) {
                case OS_TASK_STATE_RDY:
                     OS_RdyListRemove(p_tcb);                   // 把当前任务从就绪表中删除
                     p_tcb->Prio = OSTCBCurPtr->Prio;           // 提升拥有互斥信号量的任务的优先级
                     OS_PrioInsert(p_tcb->Prio);                // 更新优先级位映射表
                     OS_RdyListInsertHead(p_tcb);               // 插入到任务就绪表中
                     break;
                case OS_TASK_STATE_DLY:
                case OS_TASK_STATE_DLY_SUSPENDED:
                case OS_TASK_STATE_SUSPENDED:
                     p_tcb->Prio = OSTCBCurPtr->Prio;           // 仅仅提高拥有互斥信号量的任务的优先级
                     break;
                case OS_TASK_STATE_PEND:                        // 改变在挂起表中的位置
                case OS_TASK_STATE_PEND_TIMEOUT:
                case OS_TASK_STATE_PEND_SUSPENDED:
                case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
                     OS_PendListChangePrio(p_tcb,
                                           OSTCBCurPtr->Prio);  // 改变挂起表中的优先级
                     break;
    
                default:
                     OS_CRITICAL_EXIT();                        // 退出临界区
                     *p_err = OS_ERR_STATE_INVALID;
                     return;
            }
        }
    
        OS_Pend(&pend_data,                                     // ???
                 (OS_PEND_OBJ *)((void *)p_mutex),
                 OS_TASK_PEND_ON_MUTEX,
                 timeout);
    
        OS_CRITICAL_EXIT_NO_SCHED();                            // 退出临界区,不调度
        OSSched();                                              // 执行调度程序
    
        CPU_CRITICAL_ENTER();                                   // 进入临界区
        switch (OSTCBCurPtr->PendStatus) {
            case OS_STATUS_PEND_OK:                             // 得到互斥信号量
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = OSTCBCurPtr->TS;
                 }
                 *p_err = OS_ERR_NONE;
                 break;
            case OS_STATUS_PEND_ABORT:                          // 等待被禁止
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = OSTCBCurPtr->TS;
                 }
                 *p_err = OS_ERR_PEND_ABORT;
                 break;
            case OS_STATUS_PEND_TIMEOUT:                        // 等待超时
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = (CPU_TS  )0;
                 }
                 *p_err = OS_ERR_TIMEOUT;
                 break;
            case OS_STATUS_PEND_DEL:                            // 互斥信号量被删除
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = OSTCBCurPtr->TS;
                 }
                 *p_err = OS_ERR_OBJ_DEL;
                 break;
            default:
                 *p_err = OS_ERR_STATUS_INVALID;
                 break;
        }
        CPU_CRITICAL_EXIT();                                    // 退出临界区
    }

    6.任务释放互斥型信号量使用OSMutexPost(),它的定义位于os_mutex.c中。

    void  OSMutexPost (OS_MUTEX  *p_mutex,
                       OS_OPT     opt,
                       OS_ERR    *p_err)                           // 636行 - 727行
    {
        OS_PEND_LIST  *p_pend_list;
        OS_TCB        *p_tcb;
        CPU_TS         ts;
        CPU_SR_ALLOC();                                         // 声明变量cpu_sr,用来临时保存CPU的状态寄存器
    
    #ifdef OS_SAFETY_CRITICAL                                   // 允许进行系统安全性检查
        if (p_err == (OS_ERR *)0) {
            OS_SAFETY_CRITICAL_EXCEPTION();
            return;
        }
    #endif
    
    #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u                      // 允许进行ISR调用检查
        if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              // 不允许在ISR中调用该函数
           *p_err = OS_ERR_POST_ISR;
            return;
        }
    #endif
    
    #if OS_CFG_ARG_CHK_EN > 0u                                  // 允许进行参数检查
        if (p_mutex == (OS_MUTEX *)0) {                         // 无效参数
            *p_err = OS_ERR_OBJ_PTR_NULL;
            return;
        }
    #endif
    
    #if OS_CFG_OBJ_TYPE_CHK_EN > 0u                             // 允许进行目标类型检查
        if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) {               // 该对象不是互斥型信号量
            *p_err = OS_ERR_OBJ_TYPE;
            return;
        }
    #endif
    
        CPU_CRITICAL_ENTER();                                   // 进入临界区
        if (OSTCBCurPtr != p_mutex->OwnerTCBPtr) {              // 当前任务不是拥有该互斥型信号量的任务
            CPU_CRITICAL_EXIT();                                // 退出临界区
            *p_err = OS_ERR_MUTEX_NOT_OWNER;
            return;
        }
    
        OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();                  // 进入临界区,使能中断
        ts          = OS_TS_GET();                              // 获取时间戳
        p_mutex->TS = ts;
        p_mutex->OwnerNestingCtr--;                             // 减少互斥信号量的嵌套层数
        if (p_mutex->OwnerNestingCtr > (OS_NESTING_CTR)0) {     // 嵌套层数不为0,表示操作未完成
            OS_CRITICAL_EXIT();                                 // 退出临界区
            *p_err = OS_ERR_MUTEX_NESTING;
            return;
        }
    
        p_pend_list = &p_mutex->PendList;                       // 获取挂起表
        if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0) {         // 挂起表为空(没有任务等待该互斥信号量)
            p_mutex->OwnerTCBPtr     = (OS_TCB       *)0;
            p_mutex->OwnerNestingCtr = (OS_NESTING_CTR)0;
            OS_CRITICAL_EXIT();                                 // 退出临界区
            *p_err = OS_ERR_NONE;
            return;
        }
                                                                // 挂起表不为空
        if (OSTCBCurPtr->Prio != p_mutex->OwnerOriginalPrio) {  // 任务的当前优先级与它之前的优先级不同
            OS_RdyListRemove(OSTCBCurPtr);                      // 把当前任务从就绪表中删除
            OSTCBCurPtr->Prio = p_mutex->OwnerOriginalPrio;     // 恢复其之前的优先级
            OS_PrioInsert(OSTCBCurPtr->Prio);                   // 更新优先级位映射表
            OS_RdyListInsertTail(OSTCBCurPtr);                  // 插入到就绪表中的尾部
            OSPrioCur         = OSTCBCurPtr->Prio;
        }
                                                                // 获取挂起表中的头部的OS_TCB
        p_tcb                      = p_pend_list->HeadPtr->TCBPtr;
        p_mutex->OwnerTCBPtr       = p_tcb;                     // 给互斥型信号量一个新的拥有者
        p_mutex->OwnerOriginalPrio = p_tcb->Prio;
        p_mutex->OwnerNestingCtr   = (OS_NESTING_CTR)1;
    
        OS_Post((OS_PEND_OBJ *)((void *)p_mutex),               // 发送互斥型信号量
                (OS_TCB      *)p_tcb,
                (void        *)0,
                (OS_MSG_SIZE  )0,
                (CPU_TS       )ts);
    
        OS_CRITICAL_EXIT_NO_SCHED();                            // 退出临界区,不调度
    
        if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) {
            OSSched();                                          // 执行调度程序
        }
        *p_err = OS_ERR_NONE;
    }
    展开全文
  • 什么是进程? 进程是一个程序正在执行的实例。... 当内核产生一个新的PID,生成对应的用于管理的数据结构,并为运行程序代码分配了必要的资源,一个新的进程就产生了。 什么是线程? 线程是进程的一个
  • 互斥量的实现进程中的信号量(无名信号量)是类似的,当然,信号量也可以用于线程,区别在于初始化的时候,其本质都是P/V操作。编译时,记得加上-lpthread或-lrt哦。  一、互斥量  1、初始化销毁:  ...
  • 互斥量的实现进程中的信号量(无名信号量)是类似的,当然,信号量也可以用于线程,区别在于初始化的时候,其本质都是P/V操作。编译时,记得加上-lpthread或-lrt哦。  有关进程间通信(消息队列)见:进程间通信之...
  • 先上图,进程同步、互斥的概念。 进程具有异步性的特征,异步性是指各个并发执行...这些制约管理直接来自进程互斥合作。 、 上图是进程互斥的例子。 临界区是访问临界资源的地方。进入区和退出区是负责实现互斥..
  • 存在三种高级抽象方法,分别是锁,信号量与条件变量,其中锁也在上面那篇中讨论过了,这里主要是讨论信号量与条件变量。同步互斥的层次结构如下图所示: 信号量 为什么要引入信号量? 前面我们已经用锁机制方便的...
  • 目录一、学习的知识点PCB和进程PCB包括进程线程进程和线程信号量互斥锁应用场景二、上课没有听懂或者没有理解的地方三、当天学习的收获 一、学习的知识点 ls -a 显示隐藏文件 cd ~ 回到home目录 每个文件夹都有两...
  • 并发导致竟态,从而导致对共享数据的非控制访问,产生非预期结果,我们要避免竟态的发生。遵循以下原则:1,尽量避免资源...管理技术通常为“锁定”或者“互斥”,保证任何时刻只有一个执行线程可操作共享资源。 ...
  • (1)信号量:是一种特殊的变量,表现形式是一个整形S和一个队列。 (2)P操作:S=S-1,若S<0,进程暂停执行,进入等待队列。 (3)V操作:S=S+1,若S<=0,唤醒等待队列中的一个进程。 互斥控制 P...
  • 和进程间的信号量类似,都是管理临界资源的,都有P、V操作,只不过它的P、V操作是用下面的函数接口实现的int sem_wait(sem_t *sem);P操作 资源 -1;申请资源int sem_post(sem_t *sem);V操作 资源 +1;释放资源1#...
  • UC/OS II事件管理(2)之信号量管理

    千次阅读 2015-09-09 17:23:33
    信号量在资源互斥共享 任务同步通信中有着广泛的应用。信号量也是事件中的种,信号量的函数实现在ucos的os_sem.c文件中。 信号量是一个非负整数,当请求一个使用信号量来表示的资源时,进程需要先读取信号量的值来...
  • 也可以简单的理解为,信号量是多把锁,同时允许多个线程来更改数据,而Python信号量与互斥锁的关系信号量的一个特殊用法是互斥量。互斥量是初始值为 1 的信号量,可以实现数据、资源的互斥访问。Python信号量使用...
  • 任何时候,位于内存中的程序可以使用系统中的一切资源,不可能有其他程序之竞争; 封闭性指的是,程序的运行,在一个封闭的环境下运行的,不会被别的程序干扰。只有一个进程。独占系统资源,在操作系统中,进程是...
  • 逐渐操作系统也慢慢成型,随之而来的问题也出现了,例如计算机系统资源有一些是不允许被同一段时间内被访问的,一个进程的执行需要另外的进程执行完毕,这个进程才可以执行,也就是进程的互斥与同步。 操作系统可以...
  • 进程同步 进程同步:指对多个相关进程在执行次序上进行协调; 同步的任务:使系统中各进程之间能有效地共享资源和相互合作,从而使程序的执行...信号量机制; 管程机制 进程同步的基本概念 两种形式的制约关系 临...
  • 信号量本身不具有数据交换的功能,只是起到一个管理通信资源的作用,实际上是计数器和等待队列。在进程通信的过程中只负责数据操作的互斥和同步功能。 信号量就是具有原子性的计数器,相当于一把锁,在每个进程要...
  • 考点:本题考查操作系统进程管理同步与互斥方面的基础知识。 信号量S P是信号量S-1 V是信号量S+1 解答: 由于仓库能容纳n个产品,需要设置一个信号量S1,且初值为n,表示仓库有存放n个产品的空间,可以将产品送
  • 什么是进程同步 进程互斥的原则 进程互斥的软件实现方法 1、单标志法 2、双标志先检查法 3、双标志后检查法 4、Peterson 算法 进程互斥的硬件实现方法 ...信号量机制实现进程互斥 信号量机制实现进程同步 - 前 V 后

空空如也

空空如也

1 2 3 4 5 ... 18
收藏数 353
精华内容 141
关键字:

互斥信号量管理与信号量管理