木子剑
生命不熄,学习不止!

关于互斥锁,看看官方的描述。

 

 

经过阅读了解后,觉得可以用一些事情来理解这个互斥锁的理念。

第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);
    }
}

如果不加锁,这种测试出错的概率是多少?不知道有没有大神对比过,比竟这只是一种思想,应该找一个更权威测试例程吧。。。。

posted on 2021-08-20 09:15  木子剑  阅读(104)  评论(0编辑  收藏  举报