良许Linux教程网 干货合集 FreeRTOS多任务之间的通信——四种信号灯

FreeRTOS多任务之间的通信——四种信号灯

四种信号灯的介绍

本文将介绍四种常见的信号灯:计数信号灯,二值型信号灯,互斥信号灯和递归互斥信号灯。

  1. 计数信号灯:计数信号灯可以看作是长度大于1的队列。它的主要作用是限制线程的访问数量,确保共享资源的安全访问。当资源可用时,线程可以获取一个信号并使用该资源,当资源不可用时,线程将被阻塞,直到资源再次可用。

  2. 二值型信号灯:二进制信号灯可以看作是长度为1的队列。二值型信号灯通常用于同步线程的运行,可以确保在一个线程完成之前另一个线程无法继续执行。它与互斥锁很相似,但适用于同步任务的场景。

  3. 互斥信号灯:互斥锁和二元信号量非常相似,但有微妙的差别。互斥锁包含一个优先级继承机制,通常用于确保多个线程不能同时访问共享资源,以避免竞态条件。

  4. 递归互斥信号灯:这种信号灯没有像前面几种信号灯那样被广泛使用。主要提供递归互斥锁的API。

计数信号灯

API

创建计数信号灯:xSemaphoreCreateCounting()函数

xSemaphoreHandle xSemaphoreCreateCounting (
unsigned portBASE_TYPE uxMaxCount, 
unsigned portBASE_TYPE uxInitialCount 
)
uxMaxCount:可以达到的最大计数值。
uxInitialCount:信号量创建时分配的初始值
返回:已创建的信号量句柄,为xSemaphoreHandle 类型,如果信号量无法创建则为NULL

删除信号量void vSemaphoreDelete()

void vSemaphoreDelete( SemaphoreHandle_t xSemaphore )
xSemaphore:信号量句柄
Demo

一个初始化函数,一个获取函数

static SemaphoreHandle_t xSemaphore_count_by = NULL;
void count_semaphore_init(void *param)
{
    /*信号量的计数最大值将为5,初始值为1*/
    xSemaphore_count_by=xSemaphoreCreateCounting(5,1);
    /*再来一个*/
    xSemaphoreGive( xSemaphore_count_by );
    if(xSemaphore_count_by == NULL)
    {
        /*创建互斥信号量失败,可以写自己的处理机制*/
        printf("[%s]can't create  count_semaphore_init!\n",__func__);
    }
    vTaskDelete( NULL );
}
void count_semaphore_demo(void *param)
{
    for(;;)
    {
        /*判断这个互斥信号量是不是被创建*/
        if(xSemaphore_count_by != NULL)
        {
            /*如果信号量无效,则最多等待10个系统节拍周期。*/  
            if( xSemaphoreTake( xSemaphore_count_by,(TickType_t)10) == pdTRUE )  
            {            
                   /*获取了信号量可以进行逻辑操作*/
                 printf("[%s] Success!\n",__func__);
                 /*释放互斥信号量*/
                 #if 0
                if(xSemaphoreGive( xSemaphore_count_by )==pdFALSE)
                {
                    /*错误处理*/
                    printf("[%s]xSemaphoreGive error!\n",__func__);
                }
                #endif
            }  
            else  
            {  
                /*错误处理*/
               printf("[%s] error!\n",__func__);
            }  
        }
        vTaskDelay(500);
    }
    vTaskDelete( NULL );
}

main函数(只写了主要的函数)

if(xTaskCreate(count_semaphore_init, "count_semaphore_init", 512, NULL,2, NULL) != pdPASS){
            printf("[%s] count_semaphore_init error\n",__func__);
    }
    if(xTaskCreate(count_semaphore_demo, "mutex_semaphore_demo", 512, NULL,1, NULL) != pdPASS){
        printf("[%s] count_semaphore_demo error\n",__func__);
    }
Log

可以在这里看到获取了两次信号量

[count_semaphore_demo] Success!
[count_semaphore_demo] Success!
[count_semaphore_demo] error!
[count_semaphore_demo] error!

二值型信号灯

对API的介绍

创建二值型信号量vSemaphoreCreateBinary()

void vSemaphoreCreateBinary( xSemaphoreHandle xSemaphore )
xSemaphore :创建的二值型信号量

或者是下面的一种方式

xSemaphoreHandle  xSemaphoreCreateBinary()
返回值:创建的二值型信号量

触发二值型信号量:xSemaphoreGive() (我在这里用的是触发这两个字我觉得这个比较合适)

xSemaphoreGive (
xSemaphoreHandle xSemaphore )
xSemaphore 即将释放的信号量的句柄,在信号量创建是返回
返回值:如果信号量成功释放返回pdTRUE,如果发生错误则返回pdFALSE。

获取二值型信号量xSemaphoreTake()

xSemaphoreTake (
xSemaphoreHandle xSemaphore, 
portTickType xBlockTime 
)
xSemaphore,:将被获得的信号量句柄,此信号量必须已经被创建
xBlockTime :等待信号量可用的时钟滴答次数
返回值:如果成功获取信号量则返回pdTRUE, 超时则返回pdFALSE
Demo

构建三个任务,一个初始化的任务,一个发送信号的任务,一个进行接收的任务

static SemaphoreHandle_t xSemaphore_by = NULL;
void semaphore_init(void *param)
{
    /*初始化资源*/
    xSemaphore_by=xSemaphoreCreateBinary();    
    if(xSemaphore_by == NULL)
    {
        /*创建二值信号量失败,可以写自己的处理机制    我这里做的打印*/
        printf("[%s]can't create  xSemaphore!\n",__func__);
    }
    vTaskDelete( NULL );
}
void semaphore_send(void *param)
{ 
    for(;;)
    {
        /*判断是否创建了这个二值信号量*/
         if( xSemaphore_by != NULL )  
        {
            /*做个延时这样可以方便从log看出结果*/
             vTaskDelay(4000);
            if(xSemaphoreGive( xSemaphore_by )==pdFALSE)
            {
                /*错误处理*/
            }
        } 
        vTaskDelay(500);
    } 
    vTaskDelete( NULL );
}

void semaphore_achieve(void *param)
{
    for(;;)
    {
         if( xSemaphore_by != NULL )  
        {  
            /*如果信号量无效,则最多等待10个系统节拍周期。*/  
            if( xSemaphoreTake( xSemaphore_by,(TickType_t)10) == pdTRUE )  
            {            

                 printf("[%s]achieve Success!\n",__func__);
            }  
            else  
            {  
                /*错误处理*/
               printf("[%s]achieve error!\n",__func__);
            }  
        } 
        vTaskDelay(100);
    }
    vTaskDelete( NULL );
}

构建一个main函数:创建三个任务(这个是伪代码没有对内核启动等操作)

if(xTaskCreate(semaphore_init, "semaphore_init", 1024, NULL,2, NULL) != pdPASS){
        printf("[%s] semaphore_init error\n",__func__);
    }
    if(xTaskCreate(semaphore_achieve, "semaphore_achieve", 1024,NULL,1, NULL) != pdPASS){
            printf("[%s] semaphore_achieve error\n",__func__);
    }
    if(xTaskCreate(semaphore_send, "semaphore_send", 1024,NULL,1, NULL) != pdPASS){
            printf("[%s] semaphore_send error\n",__func__);
    }
log:(在这里只打印一部分log)
[semaphore_achieve]achieve error!
[semaphore_achieve]achieve error!
[semaphore_achieve]achieve error!
[semaphore_achieve]achieve error!
[semaphore_achieve]achieve Success!

互斥信号灯

API

xSemaphoreHandle xSemaphoreCreateMutex(void)

返回:已创建的互斥锁信号量句柄,需要为xSemaphoreHandle类型

获取和释放信号量和上面的二值信号灯是一致的

Demo

构建两个任务,一个初始化任务,一个获取和释放的任务

static SemaphoreHandle_t xSemaphore_mutex_by = NULL;
void mutex_semaphore_init(void *param)
{
    xSemaphore_mutex_by=xSemaphoreCreateMutex();
    if(xSemaphore_mutex_by == NULL)
    {
        /*创建互斥信号量失败,可以写自己的处理机制*/
        printf("[%s]can't create  xSemaphore!\n",__func__);
    }
    vTaskDelete( NULL );
}
void mutex_semaphore_demo(void *param)
{
    for(;;)
    {
        /*判断这个互斥信号量是不是被创建*/
        if(xSemaphore_mutex_by != NULL)
        {
            /*如果信号量无效,则最多等待10个系统节拍周期。*/  
            if( xSemaphoreTake( xSemaphore_mutex_by,(TickType_t)10) == pdTRUE )  
            {            
                   /*获取了信号量可以进行逻辑操作*/
                 printf("[%s] Success!\n",__func__);
                 /*释放互斥信号量*/
                if(xSemaphoreGive( xSemaphore_mutex_by )==pdFALSE)
                {
                    /*错误处理*/
                    printf("[%s]xSemaphoreGive error!\n",__func__);
                }
            }  
            else  
            {  
                /*错误处理*/
               printf("[%s] error!\n",__func__);
            }  
        }
        vTaskDelay(500);
    }
    vTaskDelete( NULL );
}

Mian函数:

int main()
{
    if(xTaskCreate(mutex_semaphore_init, "mutex_semaphore_init", 512, NULL,2, NULL) !=pdPASS)
    {
        printf("[%s] mutex_semaphore_init error\n",__func__);
    }
    if(xTaskCreate(mutex_semaphore_demo, "mutex_semaphore_demo", 512, NULL,1, NULL) != pdPASS)
    {
        printf("[%s] mutex_semaphore_demo error\n",__func__);
    }
    vTaskStartScheduler();
    for(;;);
}
log:(在这里只打印一部分log)
[mutex_semaphore_demo] Success!
[mutex_semaphore_demo] Success!
[mutex_semaphore_demo] Success!
[mutex_semaphore_demo] Success!
[mutex_semaphore_demo] Success!
[mutex_semaphore_demo] Success!

递归互斥

API

创建:

xSemaphoreHandle xSemaphoreCreateRecursiveMutex( void )
返回:已创建的互斥锁信号量为xSemaphoreHandle类型句柄

接收的释放和上面的三个不相同

接收:
xSemaphoreTakeRecursive( xSemaphoreHandle xMutex, portTickType xBlockTime )
参数:
xMutex 将被获得的互斥锁句柄,此句柄由xSemaphoreCreateRecursiveMutex()返回
xBlockTime 等待信号量可用的时钟滴答次

返回值:
如果成功获取信号量则返回pdTRUE,如果xBlockTime超时而信号量还未可用则返回pdFALSE
释放:
xSemaphoreGiveRecursive( xSemaphoreHandle xMutex )
参数: 
xMutex:将被释放的互斥锁的句柄,由 xSemaphoreCreateRecursiveMutex()返回

返回值: 
如果信号量成功释放则为pdTRUE

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

137e00002230ad9f26e78-265x300
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部