《FreeRTOS多任务之间的通信》(四种信号灯)
来源:互联网 发布:布尔玛和孙悟空 知乎 编辑:程序博客网 时间:2024/06/05 19:11
四种信号灯的介绍
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
阅读全文