关于互斥锁,看看官方的描述。
经过阅读了解后,觉得可以用一些事情来理解这个互斥锁的理念。
第1个事情, TX官方是用三个任务,同优先级,同时间段访问一个公共资源(以变量值),以此产生资源竟争。我们再延伸想
一下, 假设我有个I2C外设,这个外设是芯片外部的一个传感器IC,当有多个任务要访问时,这个时候外部I2C芯片只能
同一时间服务一个任务,这时候互斥锁就可以处理这样的资源竟争。
第2个事情, 再比如一个渣男或渣女,同时间脚踩几条船时,在和A情人约的时候,这个时间上肯定会拒绝其他情人约会(状态加锁),
明天我加班,我没空,或有有其他事情要忙等等进反馈其他情人。当过了与A情人时间段后, 就会对其他情人说,现在有空了,
你过来吧(状态解锁),这个时候在等待解锁的情人,立刻获得约会资格,这个渣男或渣女会再一次进行状态加锁。
亲!!我没有其他意思,也希望大家不要做这个“渣男或渣女”哈哈,只是想表达和理解互斥锁的深层理念,他源于生活一些事情。。
回到TencentOS-tiny的互斥锁上面,用一样的方法测试一下互斥锁, 我们先在
TencentOS-tiny\board\SWM320_DISCOVERY\BSP\Src下新建一个测试.C文件,并加载到IAR里面去,我取名叫tOS_mutex.c,
tOS_mutex.c文件内容为:
#include "cmsis_os.h" k_mutex_t mutex; // 互斥锁 int number = 0 ; // 共同数值资源 #define STK_SIZE 1024 /* --------------------------共同资源处理----------------------------------- */ void count_sample_code(void) { tos_mutex_pend(&mutex); number=0; number+=1; number+=2; number+=3; printf("test_mutex\n"); tos_mutex_post(&mutex); } /* ---------------------------多个任务操作同一个资源------------------------ */ //task1 void task1_mutex(void *pdata); osThreadDef(task1_mutex, osPriorityNormal, 1, STK_SIZE); void task1_mutex(void *pdata) { while(1) { number = 0 ; osDelay(300); count_sample_code(); printf("task1 number=%d\n",number); osDelay(100); } } //task2 void task2_mutex(void *pdata); osThreadDef(task2_mutex, osPriorityNormal, 1, STK_SIZE); void task2_mutex(void *pdata) { while(1) { osDelay(300); count_sample_code(); printf("task2 number=%d\n",number); osDelay(200); } } //task3 void task3_mutex(void *pdata); osThreadDef(task3_mutex, osPriorityNormal, 1, STK_SIZE); void task3_mutex(void *pdata) { while(1) { osDelay(300); count_sample_code(); printf("task3 number=%d\n",number); osDelay(300); } } /*-------------------------测试的应用函数入口--------------------------------*/ void application_mutex(void *arg) // mutex的测试 { //创建一个mutex量 tos_mutex_create(&mutex); //分别创建任务,用于验证互斥锁 osThreadCreate(osThread(task1_mutex), NULL); osThreadCreate(osThread(task2_mutex), NULL); osThreadCreate(osThread(task3_mutex), NULL); }
然后我们在mcu_init.h新增:
最后在main,c调用应用函数
最后仿真效果为
时间:2021-08-22
我昨天加了TX的技术QQ群,大佬说要以TencentOS-tiny\doc的 【04.Development_Manual】和【05.SDK_Manual】进行学习入门,
看了Development_Manual的line:401互斥例子,就是把共用资源由数值变量变成了数组而已,其本质没有区别。
又出于好奇,如果没有互斥锁数据会不会错乱呢?于是我把互斥全部去掉了,仿真出来的数据竟然是对的,哈哈。看来这个例程不足
测出互斥重要性,虽然操作不安全,但数据打印来看并没有出现异常。。。。。
原来的tOS_mutex.c改为:
1 #include "tos_k.h" 2 #include "mcu_init.h" 3 4 #define STK_SIZE_TASK_WRITER 512 // 任务栈大小 5 #define STK_SIZE_TASK_READER 512 6 7 // 写入数组,将writer[]数值写入resource临界区. 8 k_stack_t stack_task_writer[STK_SIZE_TASK_WRITER]; 9 10 // 读取数组,从resource临界区读取数值到reader[] 11 k_stack_t stack_task_reader[STK_SIZE_TASK_READER]; 12 13 // 设一片临界区内存资源 14 static uint32_t critical_resource[3]; 15 16 17 k_task_t task_writer; // 任务句柄 18 k_task_t task_reader; 19 extern void entry_task_writer(void *arg); // 任务回调函数 20 extern void entry_task_reader(void *arg); 21 22 // mutex句柄,用于resource[]资源加锁或解锁 23 k_mutex_t critical_resource_locker; 24 25 26 /*--------此函数向临界区共享内存写入-----------------------------------------*/ 27 static void write_critical_resource(int salt) 28 { 29 size_t i = 0; 30 printf("writting critical resource:\n"); 31 for (i = 0; i < 3; ++i) { 32 printf("%d\t", salt + i); 33 critical_resource[i] = salt + i; 34 } 35 printf("\n"); 36 } 37 38 39 /*--------此函数从临界区共享内存读取-----------------------------------------*/ 40 static void read_critical_resource(void) 41 { 42 size_t i = 0; 43 printf("reading critical resource:\n"); 44 for (i = 0; i < 3; ++i) { 45 printf("%d\t", critical_resource[i]); 46 } 47 printf("\n"); 48 } 49 50 51 /*---------task_w 在向临界区写入数据之前,先尝试获取临界区保护锁----已去掉mutex---------*/ 52 void entry_task_writer(void *arg) 53 { 54 size_t salt = 0; 55 while (K_TRUE) { 56 write_critical_resource(salt); 57 tos_task_delay(1000); 58 ++salt; 59 } 60 } 61 62 63 /*---------task_r 读取临界区数据之前,先尝试获取临界区保护锁-----已去掉mutex------------*/ 64 void entry_task_reader(void *arg) 65 { 66 while (K_TRUE) { 67 read_critical_resource(); 68 tos_task_delay(1000); 69 } 70 } 71 72 73 /*-------------------------测试的应用函数入口--------------------------------*/ 74 void application_mutex(void *arg) // mutex的测试 75 { 76 // 创建临界区保护互斥锁 77 tos_mutex_create(&critical_resource_locker); 78 79 // 创建任务,进行资源竟刍 80 tos_task_create(&task_writer, "writer", entry_task_writer, NULL, 81 4, stack_task_writer, STK_SIZE_TASK_WRITER, 0); 82 tos_task_create(&task_reader, "reader", entry_task_reader, NULL, 83 4, stack_task_reader, STK_SIZE_TASK_READER, 0); 84 }
在线仿真:
没有改之前的task源码:
void entry_task_writer(void *arg) { size_t salt = 0; k_err_t err; while (K_TRUE) { // 在向临界区写入数据之前,先尝试获取临界区保护锁 err = tos_mutex_pend(&critical_resource_locker); if (err == K_ERR_NONE) { // 成功获取锁之后,向临界区写入数据 write_critical_resource(salt); // 写完数据后,释放互斥锁 tos_mutex_post(&critical_resource_locker); } tos_task_delay(1000); ++salt; } }
void entry_task_reader(void *arg) { k_err_t err; while (K_TRUE) { // 读取临界区数据之前,先尝试获取临界区保护锁 err = tos_mutex_pend(&critical_resource_locker); if (err == K_ERR_NONE) { // 成功获取锁之后,从临界区读取数据 read_critical_resource(); // 读取数据完毕后,释放互斥锁 tos_mutex_post(&critical_resource_locker); } tos_task_delay(1000); } }
如果不加锁,这种测试出错的概率是多少?不知道有没有大神对比过,比竟这只是一种思想,应该找一个更权威测试例程吧。。。。