创建、删除
互斥量是一种特殊的二进制信号量,使用互斥量时,先创建、然后去获得、释放它。使用句柄来表示一个互斥量。
SemaphoreHandle_t xSemaphoreCreateMutex( void );
返回值: 返回句柄,非NULL表示成功
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
SemaphoreHandle_t xSemaphore:,这里直接传入mutex就可以删除
上锁、开锁
上锁
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
SemaphoreHandle_t xSemaphore:信号量句柄,释放哪个信号量
返回值 :pdTRUE表示成功,如果二进制信号量的计数值已经是1,再次调用此函数则返回失败;
如果计数型信号量的计数值已经是最大值,再次调用此函数则返回失败;
开锁
BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);
SemaphoreHandle_t xSemaphore:信号量句柄,释放哪个信号量
TickType_t xTicksToWait:如果无法马上获得信号量,阻塞一会:
- 0:不阻塞,马上返回
- portMAX_DELAY: 一直阻塞直到成功,
- 其他值: 阻塞的Tick个数,可以使用pdMS_TO_TICKS()来指定阻塞时间为若干ms;
返回值 :pdTRUE表示成功
可以看到互斥量的api和信号量的api是一样的,因为互斥量的本质是一个特殊信号量,但是需要注意互斥量不能在ISR中使用;
示例
互斥量的使用场景一般是在多个任务中操作同一个变量的时候会出现使用;下面我们先创建一个三个任务同时操作一个变量的示例;
xTaskCreate((TaskFunction_t )AppTask1, /* 任务入口函数 */ (const char* )"AppTask1", /* 任务名字 */ (uint16_t )128, /* 任务栈大小 */ (void* )NULL, /* 任务入口函数参数 */ (UBaseType_t )1, /* 任务的优先级 */ NULL); /* 任务控制块指针 */ xTaskCreate((TaskFunction_t )AppTask2, /* 任务入口函数 */ (const char* )"AppTask2", /* 任务名字 */ (uint16_t )128, /* 任务栈大小 */ (void* )NULL, /* 任务入口函数参数 */ (UBaseType_t )1, /* 任务的优先级 */ NULL); /* 任务控制块指针 */ xTaskCreate((TaskFunction_t )AppTask3, /* 任务入口函数 */ (const char* )"AppTask3", /* 任务名字 */ (uint16_t )128, /* 任务栈大小 */ (void* )NULL, /* 任务入口函数参数 */ (UBaseType_t )1, /* 任务的优先级 */ NULL);
uint32_t count = 0; static void AppTask1(void *par) { while(1) { printf("task1 print count = %d\r\n", count++); } } static void AppTask2(void *par) { while(1) { printf("task2 print count = %d\r\n", count++); xSemaphoreGive( xMutex ); /* 给出互斥量 */ } } static void AppTask3(void *par) { while(1) { printf("task3 print count = %d\r\n", count++); } }
可以看到我们每个任务获取数值都跳跃了非常多的数值,因为这三个任务都是同一优先级所以我们的系统调度会不断的在这三个任务中切换,如果任务刚好处在count++的位置这时候就切换到另外一个线程的count++的位置然而执行自加的这个过程系统调度可以执行上百次最后到打印的位置我们的值已经被其他任务操作了很多次了,所以中间的很多值没有打印出来就直接打印200多这个数值,如果我们加上线程锁,那我们的线程获取到锁过后此时其他两个线程将会一直等待获取到锁的任务操作完发送了释放信号才能拿到锁才能继续操作,那我们上述的任务切换就不会再出现了;
uint32_t count = 0; SemaphoreHandle_t xMutex; #define MUTEX 1 static void AppTask1(void *par) { while(1) { #if MUTEX xSemaphoreTake(xMutex, /* 互斥量句柄 */ portMAX_DELAY); /* 等待时间 */ #endif printf("task1 print count = %d\r\n", count++); #if MUTEX xSemaphoreGive( xMutex ); /* 给出互斥量 */ #endif } } static void AppTask2(void *par) { while(1) { #if MUTEX xSemaphoreTake(xMutex, /* 互斥量句柄 */ portMAX_DELAY); /* 等待时间 */ #endif printf("task2 print count = %d\r\n", count++); #if MUTEX xSemaphoreGive( xMutex ); /* 给出互斥量 */ #endif } } static void AppTask3(void *par) { while(1) { #if MUTEX xSemaphoreTake(xMutex, /* 互斥量句柄 */ portMAX_DELAY); /* 等待时间 */ #endif printf("task3 print count = %d\r\n", count++); #if MUTEX xSemaphoreGive( xMutex ); /* 给出互斥量 */ #endif } }
#if MUTEX xMutex = xSemaphoreCreateMutex(); #endif xTaskCreate((TaskFunction_t )AppTask1, /* 任务入口函数 */ (const char* )"AppTask1", /* 任务名字 */ (uint16_t )128, /* 任务栈大小 */ (void* )NULL, /* 任务入口函数参数 */ (UBaseType_t )1, /* 任务的优先级 */ NULL); /* 任务控制块指针 */ xTaskCreate((TaskFunction_t )AppTask2, /* 任务入口函数 */ (const char* )"AppTask2", /* 任务名字 */ (uint16_t )128, /* 任务栈大小 */ (void* )NULL, /* 任务入口函数参数 */ (UBaseType_t )1, /* 任务的优先级 */ NULL); /* 任务控制块指针 */ xTaskCreate((TaskFunction_t )AppTask3, /* 任务入口函数 */ (const char* )"AppTask3", /* 任务名字 */ (uint16_t )128, /* 任务栈大小 */ (void* )NULL, /* 任务入口函数参数 */ (UBaseType_t )1, /* 任务的优先级 */ NULL);
结尾
我是凉开水白菜,我们下文见~