嵌入式操作系统内核原理和开发(消息队列).doc_第1页
嵌入式操作系统内核原理和开发(消息队列).doc_第2页
嵌入式操作系统内核原理和开发(消息队列).doc_第3页
嵌入式操作系统内核原理和开发(消息队列).doc_第4页
嵌入式操作系统内核原理和开发(消息队列).doc_第5页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

嵌入式操作系统内核原理和开发(消息队列) 消息队列是线程交互的一种方法,任务可以通过消息队列来实现数据的沟通和交换。在嵌入式系统上,这可以说这是用的最多的一种方法。通过消息队列,无论是发送者,还是接受者都可以循环地处理各种消息。而我们知道,存储消息最好的方式就是循环队列,如果消息已满,那么发送者可以把自己pend到等待队列上;而如果此时没有消息,那么接受者也可以把自己pend到等待队列上。当然实现消息队列的方法很多,甚至用户可以自己利用互斥量和信号量来实现,而嵌入式系统常常会默认提供这样的功能函数,我想主要的目的还是为了方便用户,让他们可以更多地从业务的角度来看问题,而不是把重点关注在这些底层的细节上面。 首先,我们还是看看rawos上面关于消息队列的数据结构是怎么定义的,cpp view plaincopy1 typedef struct RAW_MSG_Q 2 3 RAW_VOID *queue_start; /* Pointer to start of queue data */ 4 RAW_VOID *queue_end; /* Pointer to end of queue data */ 5 RAW_VOID *write; /* Pointer to where next message will be inserted in the Q */ 6 RAW_VOID *read; /* Pointer to where next message will be extracted from the Q */ 7 RAW_U32 size; /* Size of queue (maximum number of entries) */ 8 RAW_U32 current_numbers; /* Current number of entries in the queue */ 9 RAW_U16 blocked_send_task_numbers; /*number of blocked send task numbers */ 10 RAW_U16 blocked_receive_task_numbers; /*number of blocked send task numbers */ 11 12 RAW_MSG_Q; 13 14 typedef struct RAW_QUEUE 15 16 RAW_COMMON_BLOCK_OBJECT common_block_obj; 17 RAW_MSG_Q msg_q; 18 19 RAW_QUEUE; 上面的代码中有两段数据结构,第一段主要表示循环队列的内容,其中包括了队列首地址、队列末尾地址、当前队列读取地址、当前队列插入地址、队列大小、消息个数、阻塞的发送线程数据、阻塞的接受线程数目。而第二段数据结构就比较简单,它把通用等待结构和循环队列合在了一起,共同构成了消息队列的数据结构。 根据我们以前的经验,互斥同步数据结构的操作都会分成几个部分,当然消息队列也不例外,也会分成初始化、发送消息、接受消息、清除消息、删除消息队列等几种操作函数。当然,消息队列还是增加了一个新的选项,那就是插入消息的时候可以插入在队列的前方,还是插入在队列的尾部,这在某种程度上决定了消息的优先级。说到这,我们还是看看消息队列是怎么初始化的,cpp view plaincopy20 RAW_U16 raw_queue_create(RAW_QUEUE *p_q, RAW_U8 *p_name, RAW_VOID *msg_start, RAW_U32 number) 21 22 23 #if (RAW_QUEUE_FUNCTION_CHECK 0) 24 25 if (p_q = 0) 26 27 return RAW_NULL_OBJECT; 28 29 30 if ( msg_start = 0) 31 32 return RAW_NULL_POINTER; 33 34 35 if (number = 0) 36 37 return RAW_ZERO_NUMBER; 38 39 40 #endif 41 42 list_init(&p_q-common_block_obj.block_list); 43 44 p_q-common_block_ = p_name; 45 p_q-common_block_obj.block_way = 0; 46 p_q-msg_q.queue_start = msg_start; /* Initialize the queue */ 47 p_q-msg_q.queue_end = &msg_startnumber; 48 p_q-msg_q.write = msg_start; 49 p_q-msg_q.read = msg_start; 50 p_q-msg_q.size = number; 51 p_q-msg_q.current_numbers = 0; 52 p_q-msg_q.blocked_send_task_numbers = 0; 53 p_q-msg_q.blocked_receive_task_numbers = 0; 54 return RAW_SUCCESS; 55 56 虽然相比较之前的互斥函数,消息队列的初始化内容好像多一些。但是大家如果对循环队列的知识比较了解的话,其实也不是很复杂的。我们看到,函数除了对通用阻塞结构进行初始化之外,就是对这些循环队列进行初始化。接着,我们就可以看看消息发送函数是怎么样的,cpp view plaincopy57 static RAW_U16 internal_msg_post(RAW_QUEUE *p_q, RAW_VOID *p_void, RAW_U8 opt_send_method, RAW_U8 opt_wake_all, RAW_U32 wait_option) 58 59 RAW_U16 error_status; 60 LIST *block_list_head; 61 RAW_U8 block_way; 62 63 RAW_SR_ALLOC(); 64 65 #if (RAW_QUEUE_FUNCTION_CHECK 0) 66 67 if (raw_int_nesting) 68 69 if (wait_option != RAW_NO_WAIT) 70 71 return RAW_NOT_CALLED_BY_ISR; 72 73 74 75 if (p_q = 0) 76 77 return RAW_NULL_OBJECT; 78 79 80 if (p_void = 0) 81 82 return RAW_NULL_POINTER; 83 84 85 #endif 86 87 block_list_head = &p_q-common_block_obj.block_list; 88 89 RAW_CRITICAL_ENTER(); 90 91 /*queue is full condition, there should be no received task blocked on queue object!*/ 92 if (p_q-msg_q.current_numbers = p_q-msg_q.size) 93 94 if (wait_option = RAW_NO_WAIT) 95 RAW_CRITICAL_EXIT(); 96 return RAW_MSG_MAX; 97 98 99 else 100 101 /*system is locked so task can not be blocked just return immediately*/ 102 if (raw_sched_lock) 103 RAW_CRITICAL_EXIT(); 104 return RAW_SCHED_DISABLE; 105 106 /*queue is full and SEND_TO_FRONT method is not allowd*/ 107 if (opt_send_method = SEND_TO_FRONT) 108 109 RAW_CRITICAL_EXIT(); 110 return RAW_QUEUE_FULL_OPT_ERROR; 111 112 113 p_q-msg_q.blocked_send_task_numbers+; 114 raw_task_active-msg = p_void; 115 block_way = p_q-common_block_obj.block_way; 116 p_q-common_block_obj.block_way = RAW_BLOCKED_WAY_FIFO; 117 /*there should be no blocked received task beacuse msg exits*/ 118 raw_pend_object(&p_q-common_block_obj, raw_task_active, wait_option); 119 p_q-common_block_obj.block_way = block_way; 120 121 RAW_CRITICAL_EXIT(); 122 123 raw_sched(); 124 125 error_status = block_state_post_process(raw_task_active, 0); 126 127 return error_status; 128 129 130 131 132 133 /*Queue is not full here, there should be no blocked send task*/ 134 /*If there is no blocked receive task*/ 135 if (is_list_empty(block_list_head) 136 137 p_q-msg_q.current_numbers+; /* Update the nbr of entries in the queue */ 138 139 if (opt_send_method = SEND_TO_END) 140 141 *p_q-msg_q.write+ = p_void; 142 143 if (p_q-msg_q.write = p_q-msg_q.queue_end) 144 145 p_q-msg_q.write = p_q-msg_q.queue_start; 146 147 148 149 150 151 else 152 153 if (p_q-msg_q.read = p_q-msg_q.queue_start) 154 p_q-msg_q.read = p_q-msg_q.queue_end; 155 156 157 p_q-msg_q.read-; 158 *p_q-msg_q.read = p_void; /* Insert message into queue */ 159 160 161 162 RAW_CRITICAL_EXIT(); 163 164 return RAW_SUCCESS; 165 166 167 /*wake all the task blocked on this queue*/ 168 if (opt_wake_all) 169 170 while (!is_list_empty(block_list_head) 171 wake_send_msg(list_entry(block_list_head-next, RAW_TASK_OBJ, task_list), p_void); 172 173 174 p_q-msg_q.blocked_receive_task_numbers = 0; 175 176 177 /*wake hignhest priority task blocked on this queue and send msg to it*/ 178 else 179 180 wake_send_msg(list_entry(block_list_head-next, RAW_TASK_OBJ, task_list), p_void); 181 p_q-msg_q.blocked_receive_task_numbers-; 182 183 184 RAW_CRITICAL_EXIT(); 185 186 raw_sched(); 187 return RAW_SUCCESS; 188 189 这里消息发送函数稍显冗长,这主要是因为消息发送的情况比较复杂,方方面面考虑的情况比较多。但是整个函数处理的逻辑还是比较清晰的,只要有耐心,慢慢读下去还是没有什么问题。这里不妨和大家一起看一下消息发送函数是怎么实现的, (1)检验参数合法性,注意在中断下调用这个函数时,必须是RAW_NO_WAIT的选项,中断毕竟是不好调度的; (2) 处理消息已满的情况, a)如果线程不想等待,函数返回; b)如果禁止调度,函数返回; c)消息存储到线程的msg里面,线程把自己pend到等待队列中; d)调用系统调度函数,等待再次被调度的机会,函数返回。 (3)当前消息未满,但是当前没有等待队列,那么根据要求把消息压入循环队列,函数返回; (4)当前消息未满,且存在等待队列,说明此时已经没有消息可读, a)如果需要唤醒所有的等待线程,那么唤醒所有的线程,等待线程总数置为0; b)如果只是唤起某一个线程,那么唤醒第一个等待线程,等待线程总数自减; (5)调用系统调度函数,防止有高优先级的线程加入调度队列; (6)线程再次得到运行的机会,函数返回。 看到上面的代码,我们发现只要梳理好了代码的逻辑,其实消息发送函数也是比较好理解的。当然,有消息的发送,就必然会存在消息的接受了。此时肯定也会出现没有消息、有消息两种情况了。cpp view plaincopy190 RAW_U16 raw_queue_receive (RAW_QUEUE *p_q, RAW_U32 wait_option, RAW_VOID *msg) 191 192 193 RAW_VOID *pmsg; 194 RAW_U16 result; 195 LIST *block_list_head; 196 RAW_TASK_OBJ *blocked_send_task; 197 198 RAW_SR_ALLOC(); 199 200 #if (RAW_QUEUE_FUNCTION_CHECK 0) 201 202 if (raw_int_nesting) 203 204 return RAW_NOT_CALLED_BY_ISR; 205 206 207 208 if (p_q = 0) 209 210 return RAW_NULL_OBJECT; 211 212 213 if (msg = 0) 214 215 return RAW_NULL_POINTER; 216 217 218 #endif 219 220 block_list_head = &p_q-common_block_obj.block_list; 221 222 RAW_CRITICAL_ENTER(); 223 224 225 /*if queue has msgs, just receive it*/ 226 if (p_q-msg_q.current_numbers) 227 228 pmsg = *p_q-msg_q.read+; 229 230 if (p_q-msg_q.read = p_q-msg_q.queue_end) 231 p_q-msg_q.read = p_q-msg_q.queue_start; 232 233 234 *msg = pmsg; 235 236 /*if there are blocked_send_tasks, just reload the task msg to end*/ 237 if (p_q-msg_q.blocked_send_task_numbers) 238 239 blocked_send_task = list_entry(block_list_head-next, RAW_TASK_OBJ, task_list); 240 241 p_q-msg_q.blocked_send_task_numbers-; 242 243 *p_q-msg_q.write+ = blocked_send_task-msg; 244 245 if (p_q-msg_q.write = p_q-msg_q.queue_end) 246 247 p_q-msg_q.write = p_q-msg_q.queue_start; 248 249 250 251 raw_wake_object(blocked_send_task); 252 RAW_CRITICAL_EXIT(); 253 254 raw_sched(); 255 return RAW_SUCCESS; 256 257 258 259 p_q-msg_q.current_numbers-; 260 261 RAW_CRITICAL_EXIT(); 262 263 return RAW_SUCCESS; 264 265 266 267 268 if (wait_option = RAW_NO_WAIT) /* Caller wants to block if not available? */ 269 *msg = (RAW_VOID *)0; 270 RAW_CRITICAL_EXIT(); 271 return RAW_NO_PEND_WAIT; 272 273 274 if (raw_sched_lock) 275 RAW_CRITICAL_EXIT(); 276 return RAW_SCHED_DISABLE; 277 278 279 raw_pend_object(&p_q-common_block_obj, raw_task_active, wait_option); 280 p_q-msg_q.blocked_receive_task_numbers+; 281 282 RAW_CRITICAL_EXIT(); 283 284 raw_sched(); 285 286 RAW_CRITICAL_ENTER(); 287 288 *msg = (RAW_VOID *)0; 289 result = block_state_post_process(raw_task_active, msg); 290 291 RAW_CRITICAL_EXIT(); 292 293 return result; 294 295 296 和发送消息函数相比,接受消息的操作还是要少一些,不要紧,大家一起来看一下实现逻辑, (1)判断参数合法性; (2)如果当前存在消息, a)读取循环队列中的消息; b)判断当前是否存在等待线程,因为之前有可能存在没有压入队列的消息,那么此时压入消息,唤醒该线程即可,调用系统调度函数返回; c)没有等待线程,消息总数自减,函数返回。 (3)当前没有消息, a)线程不愿等待,函数返回; b)系统禁止调度,函数返回; c)线程将自己pend到等待队列中; d)调用系统调度函数,切换到其他线程继续运行; e)线程再次获得运行的机会,从thread结构中获取返回结果,函数返回。 和发送消息、接受消息比较起来,清除消息和删除消息的处理就比较简单了。为了说明问题,我们不妨放在一起讨论一下,cpp view plaincopy297 RAW_U16 raw_queue_flush(RAW_QUEUE *p_q) 298 299 LIST *block_list_head; 300 301 RAW_SR_ALLOC(); 302 303 RAW_TASK_OBJ *block_task; 304 305 #if (RAW_QUEUE_FUNCTION_CHECK 0) 306 307 if (p_q = 0) 308 309 return RAW_NULL_OBJECT; 310 311 312 #endif 313 314 block_list_head = &p_q-common_block_obj.block_list; 315 316 RAW_CRITICAL_ENTER(); 317 318 /*if queue is full and task is blocked on this queue, then wake all the task*/ 319 if (p_q-msg_q.current_numbers = p_q-msg_q.size) 320 while (!is_list_empty(block_list_head) 321 block_task = list_entry(block_list_head-next, RAW_TASK_OBJ, task_list); 322 raw_wake_obj

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论