FreeRTOS互斥信号量

本文完整版地址:http://http://bbs.armfly.com/read.php?tid=21381

本章节讲解FreeRTOS重要的资源共享机制---互斥信号量(Mutex,即Mutual Exclusion的缩写)。注意,建议初学者学习完前两个章节的信号量后再学习本章节的互斥信号量。

FreeRTOS中互斥信号量的源码实现是基于消息队列实现的。

本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407以及F429。

23.1 互斥信号量

23.2 互斥信号量API函数

23.3 实验例程说明

23.4 总结

23.1互斥信号量

23.1.1 互斥信号量的概念及其作用

互斥信号量的主要作用是对资源实现互斥访问,使用二值信号量也可以实现互斥访问的功能,不过互斥信号量与二值信号量有区别。下面我们先举一个通过二值信号量实现资源独享,即互斥访问的例子,让大家有一个形象的认识,进而引出要讲解的互斥信号量。

运行条件:

u 让两个任务Task1和Task2都运行串口打印函数printf,这里我们就通过二值信号量实现对函数printf的互斥访问。如果不对函数printf进行互斥访问,串口打印容易出现乱码。

u 用计数信号量实现二值信号量只需将计数信号量的初始值设置为1即可。

代码实现:

u 创建二值信号量

static SemaphoreHandle_t  xSemaphore = NULL;

static void AppObjCreate (void)

{

xSemaphore = xSemaphoreCreateBinary();

if(xSemaphore == NULL)

{

}

xSemaphoreGive(xSemaphore);

}

u 通过二值信号量实现对printf函数互斥访问的两个任务

static void vTaskLED(void *pvParameters)

{

TickType_t xLastWakeTime;

const TickType_t xFrequency = 300;

xLastWakeTime = xTaskGetTickCount();

while(1)

{

xSemaphoreTake(xSemaphore, portMAX_DELAY);

printf("任务vTaskLED在运行rn");

bsp_LedToggle(1);

bsp_LedToggle(4);

xSemaphoreGive(xSemaphore);

vTaskDelayUntil(&xLastWakeTime, xFrequency);

}

}

static void vTaskMsgPro(void *pvParameters)

{

TickType_t xLastWakeTime;

const TickType_t xFrequency = 300;

xLastWakeTime = xTaskGetTickCount();

while(1)

{

xSemaphoreTake(xSemaphore, portMAX_DELAY);

printf("任务vTaskMsgPro在运行rn");

bsp_LedToggle(2);

bsp_LedToggle(3);

xSemaphoreGive(xSemaphore);

vTaskDelayUntil(&xLastWakeTime, xFrequency);

}

}

有了上面二值信号量的认识之后,互斥信号量与二值信号量又有什么区别呢?互斥信号量可以防止优先级翻转,而二值信号量不支持,下面我们就讲解一下优先级翻转问题。

23.1.2优先级翻转问题

下面我们通过如下的框图来说明一下优先级翻转的问题,让大家有一个形象的认识。

运行条件:

u创建3个任务Task1,Task2和Task3,优先级分别为3,2,1。也就是Task1的优先级最高。

u任务Task1和Task3互斥访问串口打印printf,采用二值信号实现互斥访问。

u起初Task3通过二值信号量正在调用printf,被任务Task1抢占,开始执行任务Task1,也就是上图的起始位置。

运行过程描述如下:

u任务Task1运行的过程需要调用函数printf,发现任务Task3正在调用,任务Task1会被挂起,等待Task3释放函数printf。

u在调度器的作用下,任务Task3得到运行,Task3运行的过程中,由于任务Task2就绪,抢占了Task3的运行。优先级翻转问题就出在这里了,从任务执行的现象上看,任务Task1需要等待Task2执行完毕才有机会得到执行,这个与抢占式调度正好反了,正常情况下应该是高优先级任务抢占低优先级任务的执行,这里成了高优先级任务Task1等待低优先级任务Task2完成。所以这种情况被称之为优先级翻转问题。

u任务Task2执行完毕后,任务Task3恢复执行,Task3释放互斥资源后,任务Task1得到互斥资源,从而可以继续执行。

上面就是一个产生优先级翻转问题的现象。

23.1.3FreeRTOS互斥信号量的实现

FreeRTOS互斥信号量是怎么实现的呢?其实相对于二值信号量,互斥信号量就是解决了一下优先级翻转的问题。下面我们通过如下的框图来说明一下FreeRTOS互斥信号量的实现,让大家有一个形象的认识。

运行条件:

u创建2个任务Task1和Task2,优先级分别为1和3,也就是任务Task2的优先级最高。

u任务Task1和Task2互斥访问串口打印printf。

u使用FreeRTOS的互斥信号量实现串口打印printf的互斥访问。

运行过程描述如下:

u低优先级任务Task1执行过程中先获得互斥资源printf的执行。此时任务Task2抢占了任务Task1的执行,任务Task1被挂起。任务Task2得到执行。

u任务Task2执行过程中也需要调用互斥资源,但是发现任务Task1正在访问,此时任务Task1的优先级会被提升到与Task2同一个优先级,也就是优先级3,这个就是所谓的优先级继承(Priority inheritance),这样就有效地防止了优先级翻转问题。任务Task2被挂起,任务Task1有新的优先级继续执行。

u任务Task1执行完毕并释放互斥资源后,优先级恢复到原来的水平。由于互斥资源可以使用,任务Task2获得互斥资源后开始执行。

上面就是一个简单的FreeRTOS互斥信号量的实现过程。

23.1.4FreeRTOS中断方式互斥信号量的实现

互斥信号量仅支持用在FreeRTOS的任务中,中断函数中不可使用。

23.2互斥信号量API函数

使用如下18个函数可以实现FreeRTOS的信号量(含计数信号量,二值信号量和互斥信号):

(1)     xSemaphoreCreateBinary()

(2)    xSemaphoreCreateBinaryStatic()

(3)    vSemaphoreCreateBinary()

(4)    xSemaphoreCreateCounting()

(5)    xSemaphoreCreateCountingStatic()

(6)    xSemaphoreCreateMutex()

(7)    xSemaphoreCreateMutexStatic()

(8)    xSem"CreateRecursiveMutex()

(9)    xSem"CreateRecursiveMutexStatic()

(10)    vSemaphoreDelete()

(11)    xSemaphoreGetMutexHolder()

(12)    uxSemaphoreGetCount()

(13)    xSemaphoreTake()

(14)    xSemaphoreTakeFromISR()

(15)    xSemaphoreTakeRecursive()

(16)    xSemaphoreGive()

(17)    xSemaphoreGiveRecursive()

(18)    xSemaphoreGiveFromISR()

关于这18个函数的讲解及其使用方法可以看FreeRTOS在线版手册:

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:

#define tskBLOCKED_CHAR         ( "B" )任务阻塞

#define tskREADY_CHAR         ( "R" )任务就绪

#define tskDELETED_CHAR          ( "D" )任务删除

#define tskSUSPENDED_CHAR  ( "S" )任务挂起

程序设计:

u任务栈大小分配:

vTaskUserIF任务:2048字节

vTaskLED任务:2048字节

vTaskMsgPro任务 :2048字节

vTaskStart任务:2048字节

任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的

#define configTOTAL_HEAP_SIZE       ( ( size_t ) ( 17 * 1024 ) )

u系统栈大小分配:

uFreeROTS初始化:

int main(void)

{

__set_PRIMASK(1);

bsp_Init();

vSetupSysInfoTest();

AppTaskCreate();

AppObjCreate();

vTaskStartScheduler();

while(1);

}

u硬件外设初始化

硬件外设的初始化是在bsp.c文件实现:

void bsp_Init(void)

{

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

bsp_InitUart();

bsp_InitLed();

bsp_InitKey();

}

uFreeRTOS任务创建:

static void AppTaskCreate (void)

{

xTaskCreate( vTaskTaskUserIF,

"vTaskUserIF",

512,

NULL,

1,

&xHandleTaskUserIF ); /*任务句柄*/

xTaskCreate( vTaskLED,

"vTaskLED",

512,

NULL,

2,

&xHandleTaskLED );

xTaskCreate( vTaskMsgPro,

"vTaskMsgPro",

512,

NULL,

3,

&xHandleTaskMsgPro ); /*任务句柄*/

xTaskCreate( vTaskStart,

"vTaskStart",

512,

NULL,

4,

&xHandleTaskStart );

}

uFreeRTOS互斥信号量创建:

static void AppObjCreate (void)

{

xMutex = xSemaphoreCreateMutex();

if(xMutex == NULL)

{

}

}

u四个FreeRTOS任务的实现:

static void vTaskTaskUserIF(void *pvParameters)

{

uint8_t ucKeyCode;

uint8_t pcWriteBuffer[500];

while(1)

{

ucKeyCode = bsp_GetKey();

if (ucKeyCode != KEY_NONE)

{

switch (ucKeyCode)

{

case KEY_DOWN_K1:

xSemaphoreTake(xMutex, portMAX_DELAY);

printf("=================================================rn");

printf("任务名任务状态 优先级剩余栈 任务序号rn");

vTaskList((char *)&pcWriteBuffer);

printf("%srn", pcWriteBuffer);

printf("rn任务名运行计数使用率rn");

vTaskGetRunTimeStats((char *)&pcWriteBuffer);

printf("%srn", pcWriteBuffer);

xSemaphoreGive(xMutex);

break;

default:

break;

}

}

vTaskDelay(20);

}

}

static void vTaskLED(void *pvParameters)

{

TickType_t xLastWakeTime;

const TickType_t xFrequency = 200;

xLastWakeTime = xTaskGetTickCount();

while(1)

{

xSemaphoreTake(xMutex, portMAX_DELAY);

printf("任务vTaskLED在运行rn");

bsp_LedToggle(2);

bsp_LedToggle(3);

xSemaphoreGive(xMutex);

vTaskDelayUntil(&xLastWakeTime, xFrequency);

}

}

static void vTaskMsgPro(void *pvParameters)

{

TickType_t xLastWakeTime;

const TickType_t xFrequency = 300;

xLastWakeTime = xTaskGetTickCount();

while(1)

{

xSemaphoreTake(xMutex, portMAX_DELAY);

printf("任务vTaskMsgPro在运行rn");

bsp_LedToggle(1);

bsp_LedToggle(4);

xSemaphoreGive(xMutex);

vTaskDelayUntil(&xLastWakeTime, xFrequency);

}

}

static void vTaskStart(void *pvParameters)

{

while(1)

{

bsp_KeyScan();

vTaskDelay(10);

}

}

FreeRTOS互斥信号量相关教程

freertos 创建互斥量_FreeRTOS互斥信号量相关推荐

  1. freertos 创建互斥量_FreeRTOS的信号量和互斥量

    1. 理解如下,言简意赅的说,信号量解决同步,互斥量解决竞争. 信号量用于同步,主要任务间和中断间同步:互斥量用于互锁,用于保护同时只能有一个任务访问的资源,为资源上一把锁. 互斥量具有优先级继承,信 ...

  2. 线程同步之互斥量(互斥锁)

    1 同步的概念 所谓同步, 即同时起步,协调一致.不同的对象, 对"同步" 的理解方式略有不同. 如,设备同步,是指在两个设备之间规定一个共同的时间参考: 数据库同步, 是指让两个 ...

  3. freertos 创建互斥量_freertos任务通信

    说明 rtos内核基本上除了任务之间的调度以外,就剩下任务通信了.如果再广一点区分,任务通信也算任务调度了,它其实是为了提高内核效率而衍生出来的内核组件,为了将这些更规范,故而大家取名为信号量,邮箱, ...

  4. RTX5 | 互斥量01 - 互斥量的使用

    文章目录 一.前言 二.实验目的 三.API 3.1.osMutexAttr_t 3.2.osMutexNew 3.3.osMutexAcquire 3.4.osMutexGetOwner 3.5.o ...

  5. Linux系统编程----16(线程同步,互斥量 mutex,互斥锁的相关函数,死锁,读写锁)

    同步概念 所谓同步,即同时起步,协调一致.不同的对象,对"同步"的理解方式略有不同.如,设备同步,是指在两 个设备之间规定一个共同的时间参考:数据库同步,是指让两个或多个数据库内容 ...

  6. FreeRTOS的信号量和互斥量

    1. 理解如下,言简意赅的说,信号量解决同步,互斥量解决竞争. 信号量用于同步,主要任务间和中断间同步:互斥量用于互锁,用于保护同时只能有一个任务访问的资源,为资源上一把锁. 互斥量具有优先级继承,信 ...

  7. 5.FreeRTOS学习笔记- 互斥量

    基本概念 互斥量又称互斥信号量(本质是信号量),是一种特殊的二值信号量 互斥量 支持互斥量所有权.递归访问以及防止优先级翻转的特性,用于实现对临界资源(如显示器.打印机)的独占式访问. 任意时刻互斥量 ...

  8. FreeRTOS笔记篇:第七章 -- 资源管理(互斥锁、二进制信号量、死锁)

    测试环境如下 stm32F103C8T6 MDK keil5 stm32cube + FreeRTOS 概述 在多任务处理系统中,如果一个任务开始访问资源,但在脱离运行状态之前没有完成其访问,则有可能 ...

  9. FreeRTOS个人笔记-互斥量

    根据个人的学习方向,学习FreeRTOS.由于野火小哥把FreeRTOS讲得比较含蓄,打算在本专栏尽量细化一点.作为个人笔记,仅供参考或查阅. 配套资料:FreeRTOS内核实现与应用开发实战指南.野 ...

最新文章

  1. 使用 Java Native Interface 的最佳实践
  2. static的应用和作用
  3. c语言 linker error,[Linker error] undefined reference to `prinf'的问题!
  4. Hash表的扩容(转载)
  5. ASP.NET MVC3 异步刷新
  6. 一份来自清华的数据分析笔记,请查收!
  7. python复数类型及其特点_二级Python语言程序设计分类模拟4
  8. c语言文件实现通信录程序,学C三个月了,学了文件,用C语言写了个通讯录程序...
  9. make的时候会报错g++: Command not found
  10. mplab java失败_Microchip工程师社区 - MPLABX用PICC编译失败 - Microchip C语言编译器论坛 - 麦田论坛...
  11. 宏基v3-571G拆机
  12. APP运营推广超级攻略(2015新版)
  13. 百度地图 - js获取行政区边界范围
  14. 推荐使用Ubutun16.04亮度调节工具
  15. mac怎么压缩pdf文件最小
  16. Vue+Webpack打造todo应用(慕课学习笔记)
  17. 程序员的职场潜意识Top10
  18. 【Arduino实验13 超声波测距】
  19. 手机QQ的移动化实践之路
  20. 如何成为一个有趣的人(专栏总结)

热门文章

  1. 华为OD机试(JAVA)真题 -- 翻转英文
  2. 常见文件对应的MIMEType类型
  3. Ubuntu命令卸载软件
  4. AmazonS3(aws 云服务android sdk接入)
  5. u盘装服务器linux系统教程,U盘安装Linux详解
  6. 【开心一笑】以后我结婚,如果新郎不是你怎么办?
  7. Spring Cloud Stream消息驱动
  8. dw中html怎么做表格边框,制作1px边框表格的几种方法-网页设计,Dreamweaver
  9. 海外版“咸鱼”Carousell是什么?
  10. 【探索 Kubernetes|作业管理篇 系列 7】探究 Pod 有什么用,为什么需要它