基于RT_Thread开发STM32之互斥量

1、互斥量的基本概念:

(1)互斥量又称互斥型信号量,是一种特殊的二值信号量,它和信号量不同的是,它支持互斥量所有 权、递归访问以及防止优先级翻转的特性,用于实现对临界资源的独占式处理。任意时刻互斥量 的状态只有两种,开锁或闭锁

(2) 互斥量具有优先级继承机制。

2、互斥量的运作机制:

3、 互斥量控制块:

1 struct rt_mutex {
2 struct rt_ipc_object parent; //互斥量属于内核对象,也会在自身结构体里面包含一个内核对象
类型的成员,通过这个成员可以将互斥量挂到系统对象容器里面。互斥量从 rt_ipc_object 中
派生,由 IPC 容器管理。
3
4 rt_uint16_t value; //互斥量的值
5
6 rt_uint8_t original_priority; //持有互斥量线程的原始优先级,用来做优先级继承的保存
7 rt_uint8_t hold; //:持有互斥量的线程的持有次数,用于记录线程递归调用了多少次
获取互斥量
8
9 struct rt_thread *owner; //当前持有互斥量的线程
10 };
11 typedef struct rt_mutex *rt_mutex_t;

4、 信号量函数接口讲解:

(1)互斥量创建函数 rt_mutex_create()

互 斥 量 创 建 函 数 rt_mutex_create() 源码:

1 rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag)
2 {
3 struct rt_mutex *mutex;
4
5 RT_DEBUG_NOT_IN_INTERRUPT;
6
7 /* 分配对象 */
8 mutex = (rt_mutex_t)rt_object_allocate(RT_Object_Class_Mutex, name);
9 if (mutex == RT_NULL)
10 return mutex;
11
12 /* 初始化 IPC 对象 */
13 rt_ipc_object_init(&(mutex->parent)); 
14
15 mutex->value = 1; 
16 mutex->owner = RT_NULL; 
17 mutex->original_priority = 0xFF; 
18 mutex->hold = 0; 
19
20 /* 设置互斥量的等待模式 */
21 mutex->parent.parent.flag = flag; 
22
23 return mutex; 
24 }
25 RTM_EXPORT(rt_mutex_create);

(2)互斥量删除函数 rt_mutex_delete()

互 斥 量 删 除 函 数 rt_mutex_delete() 源码:

1 rt_err_t rt_mutex_delete(rt_mutex_t mutex)
2 {
3 RT_DEBUG_NOT_IN_INTERRUPT;
4
5 RT_ASSERT(mutex != RT_NULL); 
6
7 /* 解除所有挂起线程 */
8 rt_ipc_list_resume_all(&(mutex->parent.suspend_thread)); 
9
10 /* 删除互斥量对象 */
11 rt_object_delete(&(mutex->parent.parent));
12
13 return RT_EOK;
14 }
15 RTM_EXPORT(rt_mutex_delete);
1 /* 定义消息队列控制块 */
2 static rt_mutex_t test_mutex = RT_NULL;
3
4 rt_err_t uwRet = RT_EOK;
5
6 uwRet = rt_mutex_delete(test_mutex);
7 if (RT_EOK == uwRet)
8 rt_kprintf("互斥量删除成功!\n\n");

(3)互斥量释放函数 rt_mutex_release()

互 斥 量 释 放 函 数 rt_mutex_release() 源码:

1 rt_err_t rt_mutex_release(rt_mutex_t mutex)
2 {
3 register rt_base_t temp;
4 struct rt_thread *thread;
5 rt_bool_t need_schedule;
6
7 need_schedule = RT_FALSE;
8
9 /* 只有持有的线程可以释放互斥量,因为需要测试互斥量的所有权 */
10 RT_DEBUG_IN_THREAD_CONTEXT;
11
12 /* 获取当前线程 */
13 thread = rt_thread_self(); 
14
15 /* 关中断 */
16 temp = rt_hw_interrupt_disable();
17
18 RT_DEBUG_LOG(RT_DEBUG_IPC,
19 ("mutex_release:current thread %s, mutex value: %d, hold: %d\n",
20 thread->name, mutex->value, mutex->hold));
21
22 RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mutex->parent.parent)));
23
24 /* 互斥量只能被持有者释放 */
25 if (thread != mutex->owner) { 
26 thread->error = -RT_ERROR;
27
28 /* 开中断 */
29 rt_hw_interrupt_enable(temp);
30
31 return -RT_ERROR;
32 }
33
34 /* 减少持有量 */
35 mutex->hold --; 
36 /* 如果没有持有量了 */
37 if (mutex->hold == 0) { 
38 /* 将持有者线程更改为原始优先级 */
39 if (mutex->original_priority != mutex->owner->current_priority) {
40 rt_thread_control(mutex->owner,
41 RT_THREAD_CTRL_CHANGE_PRIORITY,
42 &(mutex->original_priority)); 
43 }
44
45 /* 唤醒阻塞线程 */
46 if (!rt_list_isempty(&mutex->parent.suspend_thread)) { 
47 /* 获取阻塞线程 */
48 thread = rt_list_entry(mutex->parent.suspend_thread.next,
49 struct rt_thread,
50 tlist); 
51
52 RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_release: resume thread: %s\n",
53 thread->name));
54
55 /* 设置新的持有者线程与其优先级 */
56 mutex->owner = thread;
57 mutex->original_priority = thread->current_priority;
58 mutex->hold ++; (11)
59
60 /* 恢复线程 */
61 rt_ipc_list_resume(&(mutex->parent.suspend_thread)); 
62
63 need_schedule = RT_TRUE;
64 } else {
65 /* 记录增加 value 的值 */
66 mutex->value ++;
67
68 /* 清除互斥量信息 */
69 mutex->owner = RT_NULL;
70 mutex->original_priority = 0xff; 
71 }
72 }
73
74 /* 开中断 */
75 rt_hw_interrupt_enable(temp);
76
77 /* 执行一次线程调度 */
78 if (need_schedule == RT_TRUE)
79 rt_schedule(); 
80
81 return RT_EOK;
82 }
83 RTM_EXPORT(rt_mutex_release);


(4)互斥量获取函数 rt_mutex_take()

互 斥 量 获 取 函 数 rt_mutex_take() 源码:

1 rt_err_t rt_mutex_take(rt_mutex_t mutex, (1)
2 rt_int32_t time) (2)
3 {
4 register rt_base_t temp;
5 struct rt_thread *thread;
6
7 /* 即使 time = 0,也不得在中断中使用此功能 */
8 RT_DEBUG_IN_THREAD_CONTEXT;
9
10 RT_ASSERT(mutex != RT_NULL);
11
12 /* 获取当前线程 */
13 thread = rt_thread_self(); (4)
14
15 /* 关中断 */
16 temp = rt_hw_interrupt_disable(); (5)
17
18 RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mutex->parent.parent)));
19
20 RT_DEBUG_LOG(RT_DEBUG_IPC,
21 ("mutex_take: current thread %s, mutex value: %d, hold: %d\n",
22 thread->name, mutex->value, mutex->hold));
23
24 /* 设置线程错误码 */
25 thread->error = RT_EOK;
26
27 if (mutex->owner == thread) {
28 /* 如果是同一个线程 */
29 mutex->hold ++; (6)
30 } else {
31 __again:
32 /*
33 * 初始状态下互斥量的值为 1。 因此,如果该值大于 0,则表示可以使用互斥量。
34 */
35 if (mutex->value > 0) { (7)
36 /* 互斥量可用 */
37 mutex->value --;
38
39 /* 记录申请互斥量的线程与它的初始化优先级 */
40 mutex->owner = thread; (8)
41 mutex->original_priority = thread->current_priority; (9)
42 mutex->hold ++; (10)
43 } else {
44 /* 如果不等待,返回超时错误代码 */
45 if (time == 0) { (11)
46 /* 设置线程错误码 */
47 thread->error = -RT_ETIMEOUT;
48
49 /* 开中断 */
50 rt_hw_interrupt_enable(temp);
51
52 return -RT_ETIMEOUT;
53 } else { (12)
54 /* 互斥量不可用, 挂起线程 */
55 RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_take: suspend thread: %s\n",
56 thread->name));
57
58 /* 判断申请互斥量线程与持有互斥量线程的优先级关系 */
59 if (thread->current_priority < mutex->owner->current_priority) {
60 /* 改变持有互斥量的线程优先级 */ (13)
61 rt_thread_control(mutex->owner,
62 RT_THREAD_CTRL_CHANGE_PRIORITY,
63 &thread->current_priority); (14)
64 }
65
66 /* 挂起当前线程 */
67 rt_ipc_list_suspend(&(mutex->parent.suspend_thread),
68 thread,
69 mutex->parent.parent.flag); (15)
70
71 /* 有等待时间,开始计时 */
72 if (time > 0) { (16)
73 RT_DEBUG_LOG(RT_DEBUG_IPC,
74 ("mutex_take: start the timer of thread:%s\n",
75 thread->name));
76
77 /* 重置线程计时器的超时时间并启动它 */
78 rt_timer_control(&(thread->thread_timer),
79 RT_TIMER_CTRL_SET_TIME,
80 &time); (17)
81 rt_timer_start(&(thread->thread_timer)); (18)
82 }
83
84 /* 开中断 */
85 rt_hw_interrupt_enable(temp);
86
87 /* 发起线程调度 */
88 rt_schedule(); (19)
89
90 if (thread->error != RT_EOK) {
91 /* 再试一次 */
92 if (thread->error == -RT_EINTR) goto __again; (20)
93
94 /* 返回错误代码 */
95 return thread->error;
96 } else {
97 /* 获取信号量成功 */
98 /* 关中断 */
99 temp = rt_hw_interrupt_disable(); (21)
100 }
101 }
102 }
103 }
104
105 /* 开中断 */
106 rt_hw_interrupt_enable(temp);
107
108 RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mutex->parent.parent)));
109
110 return RT_EOK;
111 }
112 RTM_EXPORT(rt_mutex_take);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值