zoukankan      html  css  js  c++  java
  • CMSIS-RTOS 信号量Semaphores

    信号量Semaphores

    和信号类似,信号量也是一种同步多个线程的方式,简单来讲,信号量就是装有一些令牌的容器。当一个线程在执行过程中,就可能遇到一个系统调用来获取信号量令牌,如果这个信号量包含多个令牌,线程就会继续执行,同时信号量令牌的数量就会减一。如果此时信号量中没有令牌,线程就会被置于等待状态,直到出现一个可用的令牌。在线程执行的任何位置,它都可以给信号量增加一个令牌。

    这里写图片描述

    信号量用来帮助访问程序资源,在一个线程允许访问一个信号量之前,它必须拥有一个令牌。如果没有令牌可用,它就必须等待,当线程使用完资源时,它就必须释放令牌。

    上图揭示了两个线程如何使信号量同步。首先,必须创建一个信号量,并初始化令牌数目,在上图中,信号量初始化令牌数目为1。当两个线程运行到某一点时就试图从信号量中请求一个令牌,图中第一个线程到达这个点,成功获取一个令牌,然后继续执行,第二个线程也试图获取一个令牌,但是当前信号量为空,所以它暂停执行,并进入等待状态,直到信号量中有令牌可用。

    与此同时,执行中的线程可以释放令牌给信号量,一旦释放完成,等待中的线程就会获取令牌,并离开等待状态进入准备状态。紧接着调度器就会把它调度到运行状态去执行剩下的代码。

    因为信号量保含较多的系统调用,所以想一次性全部理解有些难度,在本节,我们将首先看看如何给系统添加信号量,然后了解一下常用的信号量应用。

    在使用信号量之前,你必须先声明一个信号量容器:

    osSemaphoreId sem1;
    osSemaphoreDef(sem1);
    • 1
    • 2

    然后在线程里给信号量容器初始化一些令牌:

    sem1 = osSemaphoreCreate(osSemaphore(sem1), SIX_TOKENS);
    • 1

    有一点比较重要,就是在线程运行的过程中令牌既可以被创建也可以被销毁,举个例子,你可以初始化一个信号量,拥有0个令牌,然后用一个线程给这个信号量创建一些令牌,再使用另一个线程移除它们,这样一来,你就可以设计线程,既可以充当生产者的线程,也可以充当消费者的线程。

    一旦信号量被创建,令牌就可能被获取,并以类似事件标志的方式发送给信号量,os_sem_wait调用来阻塞线程,直到有信号量令牌可用,类似os_event_wait,当然,在这个调用中同样拥有超时机制,超时初始值是0xFFFF。

    osStatus osSemaphoreWait(osSemaphoreId semaphore_id, uint32_t millisec);
    • 1

    一旦线程完成对信号量资源的使用,它就可以给信号量容器发送一个令牌:

    osStatus osSemaphoreRelease(osSemaphoreId semaphore_id);
    • 1

    练习:信号量的信号传输

    在这个练习中,我们将看到如何配置一个信号量,并使用它在两个任务间发送信号。

    打开Pack Installer,选择”Ex 9 Semaphore Signaling”,然后复制到你的指定路径

    首先创建一个信号量sem1,然后给它初始化0个令牌:

    osSemaphoreId sem1;
    osSemaphoreDef(sem1);
    int main(void){
        sem1 = osSemaphoreCreate(osSemaphore(sem1), 0);
    • 1
    • 2
    • 3
    • 4

    第一个线程等待一个令牌被发送到信号量容器:

    void led_Thread1(void const *argument){
        for(;;){
            osSemaphoreWait(sem1, osWaitForever);
            LED_On(1);
            osDelay(500);
            LED_Off(1);
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    与此同时,第二个线程周期性的给信号量发送令牌:

    void led_Thread2(void const *argument){
        for(;;){
            LED_On(2);
            osSemaphoreRelease(sem1);
            osDelay(500);
            LED_Off(2);
            osDelay(500);
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    编译工程并启动仿真环境

    在led_Thread2任务设置断点:

    这里写图片描述

    运行代码,运行到断点,观察线程状态:

    这里写图片描述

    现在led_thread1被阻塞,等待从信号量获取一个令牌,线程1的优先级比线程2高,所以一旦令牌放入信号量,线程1就会立即进入准备状态,抢占低优先级线程,并随后启动运行。当运行到osSemaphoreWait()调用后,它又再次阻塞。

    现在单步运行(F10),观察线程及信号量的行为。

  • 相关阅读:
    vue前台(八)
    npm 淘宝镜像的配置
    详解数组中的reduce方法
    javaScript中的布尔值判断
    vue前台(七)
    vue前台(六点二)
    vue前台(六点一)
    vue前台(五)
    Android涂鸦技术及刮刮乐示例分析
    Android控件ActionBar浅析及适配2.x的方法介绍
  • 原文地址:https://www.cnblogs.com/jack-hzm/p/8098267.html
Copyright © 2011-2022 走看看