RTOS互斥信号量
概述
解决多任务共享资源冲突问题的三个方法:
- 关中断:此方法屏蔽所有中断,若中间代码过长,严重影响性能
- 调度锁:此方法不允许任务切换,若代码过长也会对性能造成较大影响
- 信号量:此方法使用信号量实现同步与互斥,但信号量不支持嵌套调用、不支持所有者,即任意任务都能进行Post操作,且无法处理优先级反转操作
解决方法:互斥信号量
- 互斥信号量使用可以用于嵌套调用的锁定次数计数器:每获取一次计数信号量+1,标记为已拥有,释放一次信号量-1,减为0表示释放此信号量
- 互斥信号量绑定唯一的任务
- 互斥信号量支持优先级继承的原始优先级
什么叫优先级反转
考虑这样一种情况:有一个低优先级的任务正占有某一互斥资源,此时一个高优先级任务正在等待此资源,与此同时还有两个中等优先级的任务正在交替运行,这就导致了死锁:即低优先级任务由于优先级比较低,无法运行,高优先级任务因为未能占有目标资源,无法运行,而中等优先级任务则可以交替运行。
解决方法:将低优先级任务的优先级提高,即使得低优先级任务尽快运行完毕,让出资源使得高优先级任务能够运行,当低优先级任务让出资源后即恢复它的优先级,这就避免了两个中优先级任务一直运行的情况。
实现
定义
1
2
3
4
5
6
7
8
9
typedef struct _mutex {
eventCtrlBlock_t event;
uint32_t lockedCount; // 锁定次数
uint32_t ownerOriginalPriority; // 互斥锁拥有者的原始优先级
task_t* owner; // 互斥量的拥有者
}mutex_t;
初始化
1
2
3
4
5
6
void mutexInit(mutex_t* mutex) {
eventInit(&mutex->event, EVENT_TYPE_MUTEX);
mutex->lockedCount = 0;
mutex->owner = NULL;
mutex->ownerOriginalPriority = RTOS_PRIORITY_COUNT;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// 获取互斥锁
uint32_t mutexWait(mutex_t* mutex, uint32_t waitTime) {
uint32_t st = enterCritical();
if (mutex->lockedCount == 0) {
mutex->owner = currentTask;
mutex->ownerOriginalPriority = currentTask->priority;
mutex->lockedCount++;
leaveCritical(st);
return NO_ERROR;
}
if (mutex->owner == currentTask) {
mutex->lockedCount++;
leaveCritical(st);
return NO_ERROR;
}
if (currentTask->priority >= mutex->ownerOriginalPriority) {
eventWait(&mutex->event, currentTask, NULL, TASK_STATUS_WAIT_MUTEX, waitTime);
taskSched();
leaveCritical(st);
return currentTask->eventWaitResult;
}
if (currentTask->priority < mutex->ownerOriginalPriority) {
if (mutex->owner->state & TASK_STATUS_READY) {
taskSched2Unready(mutex->owner);
mutex->owner->priority = currentTask->priority;
taskSched2Ready(mutex->owner);
}
mutex->owner->priority = currentTask->priority;
eventWait(&mutex->event, currentTask, NULL, TASK_STATUS_WAIT_MUTEX, waitTime);
taskSched();
leaveCritical(st);
return currentTask->eventWaitResult;
}
leaveCritical(st);
return NO_ERROR;
}
// 获取互斥锁且不等待
uint32_t mutexGetWithNoWait(mutex_t* mutex) {
uint32_t st = enterCritical();
if (mutex->lockedCount == 0) {
mutex->owner = currentTask;
mutex->ownerOriginalPriority = currentTask->priority;
mutex->lockedCount++;
leaveCritical(st);
return NO_ERROR;
}
if (mutex->owner == currentTask) {
mutex->lockedCount++;
leaveCritical(st);
return NO_ERROR;
}
leaveCritical(st);
return ERROR_RESOURCE_UNAVAILABLE;
}
// 释放一次互斥锁
uint32_t mutexPost(mutex_t* mutex) {
uint32_t st = enterCritical();
if (currentTask != mutex->owner) {
leaveCritical(st);
return ERROR_UNMATCHED_OWNER;
}
if (mutex->lockedCount > 0) {
if (--mutex->lockedCount == 0) {
if (mutex->ownerOriginalPriority != currentTask->priority) {
taskSched2Unready(currentTask);
currentTask->priority = mutex->ownerOriginalPriority;
taskSched2Ready(currentTask);
}
task_t* task = NULL;
if ((task = eventWakeUp(&mutex->event, NULL, NO_ERROR)) != NULL) {
mutex->owner = task;
mutex->ownerOriginalPriority = task->priority;
mutex->lockedCount++;
if (task->priority < currentTask->priority) {
taskSched();
}
leaveCritical(st);
return NO_ERROR;
}
}
}
leaveCritical(st);
return NO_ERROR;
}
// 摧毁互斥锁
uint32_t mutexDestory(mutex_t* mutex) {
uint32_t count = 0;
uint32_t st = enterCritical();
if (mutex->lockedCount == 0) {
leaveCritical(st);
return count;
}
if (mutex->ownerOriginalPriority != mutex->owner->priority) {
if (mutex->owner->state & TASK_STATUS_READY) {
taskSched2Unready(mutex->owner);
mutex->owner->priority = mutex->ownerOriginalPriority;
taskSched2Ready(mutex->owner);
}
else {
mutex->owner->priority = mutex->ownerOriginalPriority;
}
}
if ((count = eventRemoveAllTask(&mutex->event, NULL, ERROR_DELETED)) > 0) {
taskSched();
}
leaveCritical(st);
return count;
}
// 查询信息
mutexInfo_t mutexGetInfo(mutex_t* mutex) {
mutexInfo_t info;
uint32_t st = enterCritical();
info.owner = mutex->owner;
if (info.owner == NULL) {
info.inheritedPriority = RTOS_PRIORITY_COUNT;
info.ownerOriginalPriority = RTOS_PRIORITY_COUNT;
}else {
info.inheritedPriority = mutex->owner->priority;
info.ownerOriginalPriority = mutex->ownerOriginalPriority;
}
info.lockedCount = mutex->lockedCount;
info.waitTaskNum = eventGetWaitNum(&mutex->event);
leaveCritical(st);
return info;
}
本文由作者按照 CC BY 4.0 进行授权