目录
三、使用Mutex(Mutual Exclusion)解决竞争冒险问题
一、通过全局变量进行任务间的数据传递
(一)volatile关键字
当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。例如:
volatile int i=10;
int a = i;
...
// 其他代码,并未明确告诉编译器,对 i 进行过操作
int b = i;
volatile 指出 i 是随时可能发生变化的,每次使用它的时候必须从 i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在 b 中。而优化做法是,由于编译器发现两次从 i读数据的代码之间的代码没有对 i 进行过操作,它会自动把上次读的数据放在 b 中。而不是重新从 i 里面读。这样以来,如果 i是一个寄存器变量或者表示一个端口数据就容易出错,所以说 volatile 可以保证对特殊地址的稳定访问。
以上是个人认为重要的知识点,详细请看C/C++ 中 volatile 关键字详解 | 菜鸟教程
Volatile关键字(记忆技巧)
1.Volatile中文译为易变的
2.使用Volatile定义的变量,在代码中每次使用都需要经过内存读取
3.防止中断突然改变其变量(因为中断改变变量直接放入内存,若在程序运行的时候直接从寄存器中读取,则会造成数据错误)
(二)程序例程
定义两个全局变量,用于记录库存和销售量
// 养成良好习惯,被多进程和中断调用的变量使用 volatile 修饰符
volatile uint32_t inventory = 100; //总库存
volatile uint32_t retailCount = 0; //线下销售量
定义一个retailTask函数,用于改变库存和销量
void retailTask(void *pvParam) {
while (1) {
//以下实现了带有随机延迟的 inventory减1;
//等效为 inventory--; retailCount++;
uint32_t inv = inventory;
for (int i; i < random(10, 100); i++) vTaskDelay(pdMS_TO_TICKS(i));
if (inventory > 0) {
inventory = inv - 1;
retailCount++;
}
};
vTaskDelay(10); //老板要求慢一些,客户升级后,可以再加快速度
}
定义showTask函数,用于展示库存和销量
void showTask(void *pvParam) {
while (1) {
printf("Inventory : %d\n", inventory);
printf(" Retail : %d\n", retailCount);
if (inventory == 0 ) {
printf("\n-----SALES SUMMARY-----\n");
printf(" Total Sales: %d\n\n", retailCount);
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}
主函数,创建两个任务
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
xTaskCreate(retailTask,
"Online Channel",
1024 * 4,
NULL,
1,
NULL);
xTaskCreate(showTask,
"Display Inventory",
1024 * 4,
NULL,
1,
NULL);
}
void loop() {
}
例程网址:用全局变量实现任务间通信
注意!!!使用全局变量大小一定要与ESP32的CPU大小一致,也就是32位
二、竞争冒险(Race Condition)问题提出
例程网址:竞争冒险
三、使用Mutex(Mutual Exclusion)解决竞争冒险问题
理解方法:
MUTEX的工作原理可以想象成
共享的资源被锁在了一个箱子里,只有一把钥匙,有钥匙的任务才能对改资源进行访问
将Mutex比喻成一把钥匙,首先创建钥匙,再取钥匙,再归还钥匙
1.Create
2.Take
3.Give
语法:
SemaphoreHandle_t xHandler; 创建Handler
xHandler = xSemaphoreCreateMutex(); 创建一个MUTEX 返回NULL,或者handler
xSemaphoreGive(xHandler); 释放
xSemaphoreTake(xHanlder, timeout); 指定时间内获取信号量 返回pdPASS, 或者pdFAIL
例程网址:使用Mutex解决冒险竞争问题
四、Mutex实例
使用MPU6050搭配LCD显示MPU6050的数据