消息缓冲队列通信机制其基本思想是根据“生产者——消费者”原理,利用内存中公用消息缓冲区实现进程间的信息交换。
在这种通信机制中,首先需要在内存中开辟若干空闲消息缓冲区,用以存放要通信的消息。每当一个进程需要向另一个进程发送消息时,便向系统申请一个空闲消息缓冲区,并把已准备好的消息复制到该缓冲区,然后把该消息缓冲区插入到接收进程的消息队列中,最后通知接收进程。接收进程接收到发送进程发来的通知后,从本进程的消息队列中摘下一消息缓冲区,取出其中的信息,然后把消息缓冲区作为空闲消息缓冲区归还给系统。系统负责管理公用消息缓冲区以及消息的传递。
1 // 消息缓冲队列
2 // 2016.1.7
3
4 #include <stdlib.h>
5 #include <dos.h>
6 #include <stdio.h>
7
8 #define GET_INDOS 0x34 /* 34H 系统功能调用 */
9 #define GET_CRIT_ERR 0x5d06 /* 5D06H号系统功能调用 */
10
11 #define BLANK -1
12 #define FINISHED 0 /* 终止 */
13 #define RUNNING 1 /* 执行 */
14 #define READY 2 /* 就绪 */
15 #define BLOCKED 3 /* 阻塞 */
16 #define NTCB 3 /* 系统线程的最大数 */
17
18 #define TL 10 /* 时间片大小 */
19 #define NBUF 2 /* 消息缓冲区数目 */
20 #define NTEXT 50 /* 文本输出大小 */
21
22
23 char far* intdos_ptr=0;
24 char far* crit_err_ptr=0;
25 int timecount=0;
26 int current=-1;
27
28 typedef unsigned int UINT16;
29
30 typedef struct/* 信号量 */
31 {
32 int value;
33 struct TCB* wq;
34 }semaphore;
35
36 semaphore mutexfb={1,NULL}; // freebuf 互斥变量 初值 1
37 semaphore sfb={2,NULL}; // 计数信号量
38 semaphore bufferSem1, bufferSem2;
39
40 // 消息缓冲区
41 // 空闲缓冲队列 freebuf(临界资源)
42 struct buffer
43 {
44 int sender; /*消息发送者的标识数 */
45 int size; /* 消息长度<=NTEXT 个字节 */
46 char text[NTEXT]; /* 消息正文 */
47 struct buffer* next; /* 指向下一个消息缓冲区的指针 */
48 } *freebuf;
49
50 /* 线程控制块 */
51 struct TCB
52 {
53 unsigned char* stack; /* 堆栈的起始地址 */
54 unsigned ss;
55 unsigned sp; /* 堆栈段址和堆栈指针 */
56 char state; /* 进程状态 */
57 char name[10]; /* 线程的外部标识符 */
58 int value; /*优先级*/
59 struct TCB* next; /* 指向控制快指针 */
60 struct buffer* mq; /* 消息缓冲队列首指针 */
61 semaphore mutex; /* 互斥信号量 */
62 semaphore sm; /* 消息缓冲队列计数信号量*/
63 }tcb[NTCB];
64
65 /* 堆栈现场保护和恢复结构体 */
66 struct int_regs
67 {
68 unsigned BP,DI,SI,DS,ES,DX,CX,BX,AX,IP,CS,Flags,off,seg;
69 };
70
71 typedef int(far* codeptr)(void);
72 void interrupt(*old_int8)(void);
73 int DosBusy(void);
74 void InitIndos(void);
75 void InitTcb();
76 void interrupt new_int8(void);
77 void interrupt swtch();
78 void send(char *receiver,char *a,int size);
79 int receive(char *sender,char *a);
80 void p(semaphore *sem);
81 void v(semaphore *sem);
82 int Create(char* name,codeptr code,int stacklen,int prio); /* 创建线程 */
83 void Destroy(int i);
84
85
86 // 1#线程
87 void f1()
88 {
89
90 while(1)
91 {
92 p(&bufferSem1);
93
94 send("f2","f1 send message to f2",NTEXT);
95
96 printf("f1 sending!\n");
97
98 v(&bufferSem2);
99 }
100 }
101
102 // 2#线程
103 void f2()
104 {
105 char a[NTEXT];
106
107 while(1)
108 {
109 p(&bufferSem2);
110
111 receive("f1",a);
112
113 printf("f2 receiving!\n");
114
115 v(&bufferSem1);
116 }
117 }
118
119
120 void InitInDos() /* 取得INDOS标志和严重错误标志地址 */
121 {
122 union REGS regs;
123 struct SREGS segregs;
124
125 regs.h.ah=GET_INDOS; /* 使用34H号系统功能调用 */
126 intdosx(®s,®s,&segregs);
127
128 intdos_ptr=MK_FP(segregs.es,regs.x.bx);
129 if(_osmajor<3)
130 crit_err_ptr=intdos_ptr+1; /* 严重错误在INDOS后一字节处 */
131 else if(_osmajor==3&&_osminor==0)
132 crit_err_ptr=intdos_ptr-1; /* 严重错误在INDOS前一字节处 */
133 else
134 {
135 regs.x.ax=GET_CRIT_ERR;
136 intdosx(®s,®s,&segregs);
137 crit_err_ptr=MK_FP(segregs.ds,regs.x.si);
138 }
139 }
140
141 int DosBusy(void) /* 判断DOS是否忙 */
142 {
143 if(intdos_ptr&&crit_err_ptr)
144 return(*intdos_ptr||*crit_err_ptr); /* DOS忙,返回严重错误标志 */
145 else
146 return(-1); /* DOS不忙 */
147 }
148
149 void InitTcb() /* 初始化线程 */
150 {
151 int i;
152
153 for(i=0;i<NTCB;i++)
154 {
155 tcb[i].state=BLANK; /* 初始状态标志 */
156 tcb[i].mq=NULL;
157 tcb[i].mutex.value=1;
158 tcb[i].mutex.wq=NULL;
159 tcb[i].sm.value=0;
160 tcb[i].sm.wq=NULL;
161 }
162 }
163
164 void Destroy(int i)
165 {
166
167 if(tcb[i].state==RUNNING)
168 {
169 disable();
170 tcb[i].state=FINISHED;
171 strcpy(tcb[i].name,NULL);
172 free(tcb[i].stack);
173 tcb[i].ss=0;
174 tcb[i].sp=0;
175 enable();
176 }
177
178 }
179
180 void over()
181 {
182 Destroy(current);
183 swtch();
184 }
185
186 int Create(char *name,codeptr code,int stacklen,int value)
187 {
188 int i;
189 char *p;
190 struct int_regs *pt;
191 unsigned int *pp;
192
193 for(i=1;i<NTCB;i++)
194 {
195 if(tcb[i].state==BLANK||tcb[i].state==FINISHED)
196 break;
197 }
198 if(i==NTCB)
199 return-1;
200
201 tcb[i].value=value;
202 strcpy(tcb[i].name,name);
203 tcb[i].stack=(p=(unsigned char*)malloc(stacklen));
204 memset(tcb[i].stack, 0xff, stacklen);
205 p=p+stacklen;
206
207 #if 0
208 pt=(struct int_regs*)p;
209 pt--;
210 pt->Flags=0x200;
211 pt->CS=FP_SEG(code);
212 pt->IP=FP_OFF(code);
213
214 pt->off=FP_OFF(over);
215 pt->seg=FP_SEG(over);
216 pt->DS=_DS;
217 pt->ES=_ES;
218 tcb[i].sp=FP_OFF(pt);
219 tcb[i].ss=FP_SEG(pt);
220 #else if
221 /*
222 pp=(UINT16 *)(p-2);
223 *(pp)=FP_SEG(over);
224 *(pp-1)=FP_OFF(over);
225 *(pp-2)=0x200;
226 *(pp-3)=FP_SEG(code);
227 *(pp-4)=FP_OFF(code);
228
229 *(pp-9)=_ES;
230 *(pp-10)=_DS;
231 tcb[i].sp=FP_OFF(pp-13);
232 tcb[i].ss=FP_SEG(pp-13);
233 */
234
235 *(p-1)=(FP_SEG(over)&0xff00)>>8;
236 *(p-2)=FP_SEG(over)&0x00ff;
237
238 *(p-3)=(FP_OFF(over)&0xff00)>>8;
239 *(p-4)=FP_OFF(over)&0x00ff;
240
241 *(p-5)=0x02;
242 *(p-6)=0x00;
243
244 *(p-7)=(FP_SEG(code)&0xff00)>>8;
245 *(p-8)=FP_SEG(code)&0x00ff;
246
247 *(p-9)=(FP_OFF(code)&0xff00)>>8;
248 *(p-10)=FP_OFF(code)&0x00ff;
249
250 *(p-19)=(_ES&0xff00)>>8;
251 *(p-20)=_ES&0x00ff;
252
253 *(p-21)=(_DS&0xff00)>>8;
254 *(p-22)=_DS&0x00ff;
255
256 tcb[i].sp=FP_OFF((UINT16 *)(p-28));
257 tcb[i].ss=FP_SEG((UINT16 *)(p-28));
258
259 #endif
260
261 tcb[i].state=READY;
262
263 return i;
264 }
265
266 void tcb_state() /* 线程状态信息 */
267 {
268 int i;
269
270 for(i=0;i<NTCB;i++)
271 if(tcb[i].state!=BLANK)
272 {
273 switch(tcb[i].state)
274 {
275 case FINISHED:
276 printf("\ntcb[%d] is FINISHED\n",i);
277 break;
278
279 case RUNNING:
280 printf("tcb[%d] is RUNNING\n",i);
281 break;
282 case READY:
283 printf("tcb[%d] is READY\n",i);
284 break;
285 case BLOCKED:
286 printf("tcb[%d] is BLOCKED\n",i);
287
288 break;
289 }
290 }
291 }
292
293 int all_finished()
294 {
295 int i;
296
297 for(i=1;i<NTCB;i++)
298 if(tcb[i].state==RUNNING||tcb[i].state==BLOCKED||tcb[i].state==READY)
299 return 0;
300
301 return 1;
302 }
303
304 int Find()
305 {
306 int i,j;
307 i=current;
308
309 while(tcb[i=((i+1)%NTCB)].state!=READY||i==current);
310
311 return i;
312 }
313
314 void interrupt new_int8(void) /* CPU 调度*/
315 {
316 int i;
317
318 (*old_int8)(); /* 指向原来时钟中断处理过程入口的中断处理函数指针 */
319 timecount++;
320
321 if(timecount==TL) /* 时间片是否到? */
322 {
323 if(!DosBusy()) /* DOS是否忙? */
324 {
325 disable();
326
327 tcb[current].ss=_SS; /* 保存现场 */
328 tcb[current].sp=_SP;
329
330 if(tcb[current].state==RUNNING)
331 tcb[current].state=READY;
332
333 i=Find();
334 if(i<0)
335 return;
336
337 _SS=tcb[i].ss;
338 _SP=tcb[i].sp;
339 tcb[i].state=RUNNING;
340 current=i;
341 timecount=0; /* 重新计时 */
342
343 enable();
344 }
345 else
346 return;
347 }
348 else
349 return;
350 }
351
352 void interrupt swtch() /* 其他原因CPU调度 */
353 {
354 int i;
355
356 if(tcb[current].state!=FINISHED
357 &¤t!=0&&tcb[current].state!=BLOCKED) /* 当前线程还没结束 */
358 return;
359
360 i=Find();
361 if(i<0)
362 return;
363
364 disable();
365 tcb[current].ss=_SS;
366 tcb[current].sp=_SP;
367
368 if(tcb[current].state==RUNNING)
369 tcb[current].state=READY; /* 放入就绪队列中 */
370
371 _SS=tcb[i].ss;
372 _SP=tcb[i].sp; /* 保存现场 */
373
374 tcb[i].state=RUNNING;
375 current=i;
376 enable();
377 }
378
379 void block(struct TCB **p) /* 阻塞原语 */
380 {
381 struct TCB *pp;
382
383 tcb[current].state=BLOCKED;
384
385 if((*p)==NULL)
386 *p=&tcb[current]; /* 阻塞队列空,直接放入 */
387 else
388 {
389 pp=*p;
390 while(pp->next)
391 pp=pp->next; /* 找到阻塞队列最后一个节点 */
392
393 pp->next=&tcb[current]; /* 放入阻塞队列 */
394 }
395 tcb[current].next=NULL;
396 swtch(); /* 重新进行CPU调度 */
397 }
398
399 void wakeup_first(struct TCB **p) /* 唤醒队首线程 */
400 {
401 struct TCB *pl;
402
403 if((*p)==NULL)
404 return;
405
406 pl=(*p);
407 (*p)=(*p)->next; /* 得到阻塞队列队首线程 */
408 pl->state=READY; /* 修为就绪状态 */
409 pl->next=NULL;
410 }
411
412 void p(semaphore *sem)
413 {
414 struct TCB **qp;
415
416 disable();
417 sem->value=sem->value-1;
418
419 if(sem->value<0)
420 {
421 qp=&(sem->wq);
422 block(qp);
423 }
424 enable();
425 }
426
427 void v(semaphore*sem)
428 {
429 struct TCB **qp;
430
431 disable();
432 qp=&(sem->wq);
433 sem->value=sem->value+1;
434
435 if(sem->value>=0)
436 wakeup_first(qp);
437
438 enable();
439 }
440
441 ///
442 // buffer
443 struct buffer*Initbuf(void)
444 {
445 struct buffer *p,*pt,*pt2;
446 int i;
447
448 pt2=pt=(struct buffer*)malloc(sizeof(struct buffer));
449 pt->sender=-1;
450 pt->size=0;
451 strcmp(pt->text,"");
452 pt->next=NULL;
453
454 for(i=0;i<NBUF-1;i++)
455 {
456 p=(struct buffer*)malloc(sizeof(struct buffer));
457 p->sender=-1;
458 p->size=0;
459 p->text[NTEXT]='\0';
460 p->next=NULL;
461 pt2->next=p;
462 pt2=p;
463 }
464
465 return pt;
466 }
467
468 // 从空闲消息缓冲队列队头上取下一缓空闲消息冲区
469 struct buffer* getbuf(void)
470 {
471 struct buffer *buf;
472
473 buf=freebuf; /* 取得缓冲队列的缓冲区*/
474 freebuf=freebuf->next;
475
476 return(buf); /* 返回指向该缓冲区的指针 */
477 }
478
479 // 将buff所指的缓冲区插到*mq所指的缓冲队列末尾
480 void insert(struct buffer **mq, struct buffer *buff)
481 {
482 struct buffer *temp;
483
484 if(buff==NULL)
485 return; /* buff为空 */
486
487 buff->next=NULL;
488 if(*mq==NULL) /* *mq为空 则直接插入*/
489 *mq=buff;
490 else
491 {
492 temp=*mq;
493 while(temp->next) /* 找到队尾 */
494 temp=temp->next;
495
496 temp->next=buff;
497 }
498 }
499
500 // 将地址a开始的size个字节发送给外部标识符为receiver的线程
501 void send(char *receiver,char *a, int size)
502 {
503 struct buffer *buff;
504 int i,id=-1;
505
506 disable();
507 for(i=0;i<NTCB;i++)
508 {
509 if(strcmp(receiver,tcb[i].name)==0)
510 {
511 id=i;
512 break;
513 }
514 }
515
516 if(id==-1)
517 {
518 printf("Error:Receiver not exist!\n");
519 enable();
520 return;
521 }
522
523 p(&sfb);
524
525 p(&mutexfb);
526 buff=getbuf();
527 v(&mutexfb);
528
529 buff->sender=current;
530 buff->size=size;
531 buff->next=NULL;
532
533 for(i=0;i<buff->size;i++,a++)
534 buff->text[i]=*a;
535
536 // 将要发送的消息放到接收者TCB的buffer中
537 p(&tcb[id].mutex);
538 insert(&(tcb[id].mq),buff);
539 v(&tcb[id].mutex);
540
541 // 用于同步
542 v(&tcb[id].sm);
543 enable();
544 }
545
546 //
547 // 获取消息缓冲区函数
548 struct buffer *remov(struct buffer **mq, int sender)
549 {
550 struct buffer *buff, *p, *q;
551 q = NULL;
552 p = *mq;
553
554 // 在消息缓冲区队列中找到其他进程发送给自己的消息
555 while((p->next != NULL) && (p->sender != sender))
556 {
557 q = p;
558 p = p->next;
559 }
560
561 // 获取消息后从队列中删除,防止重复接收
562 if(p->sender == sender)
563 {
564 buff = p;
565 if(q == NULL)
566 *mq = buff->next;
567 else
568 q->next = buff->next;
569
570 buff->next = NULL;
571 return buff;
572 }
573 else
574 return NULL;
575 }
576
577 // 接收原语
578 int receive(char *sender, char *b)
579 {
580 int i, id = -1;
581 struct buffer *buff;
582
583 disable();
584
585 // 寻找 sender
586 for(i = 0; i < NBUF; i++)
587 {
588 if(strcmp(sender, tcb[i].name) == 0)
589 {
590 id = i;
591 break;
592 }
593 }
594
595 if(id == -1)
596 {
597 enable();
598 return -1;
599 }
600
601 p(&tcb[current].sm);
602
603 p(&tcb[current].mutex);
604 buff = remov(&(tcb[current].mq), id);
605 v(&tcb[current].mutex);
606
607 if(buff == NULL)
608 {
609 v(&tcb[current].sm);
610 enable();
611 return -1;
612 }
613 // 将消息正文复制到接收区
614 strcpy(b, buff->text);
615
616 // 释放前先把标识去掉,防止重复接收
617 buff->sender = -1;
618 // 释放相应的消息缓冲区
619 p(&mutexfb);
620 insert(&freebuf, buff);
621 v(&mutexfb);
622
623 v(&sfb);
624
625 enable();
626
627 return buff->size;
628 }
629
630 void main()
631 {
632 long i, j, k;
633
634 bufferSem1.value = 1;
635 bufferSem1.wq = NULL;
636
637 bufferSem2.value = 0;
638 bufferSem2.wq = NULL;
639
640 InitInDos();
641 InitTcb();
642
643 freebuf=Initbuf();
644 old_int8=getvect(8);
645
646 strcpy(tcb[0].name,"main");
647 tcb[0].state=RUNNING;
648 tcb[0].value=0;
649 current=0;
650
651 Create("f1",(codeptr)f1,1024,5);
652 Create("f2",(codeptr)f2,1024,6);
653
654 tcb_state();
655 setvect(8,new_int8);
656
657 while(!all_finished());
658 {
659
660 printf("running!\n");
661
662 }
663
664 tcb[0].name[0]='\0';
665 tcb[0].state=FINISHED;
666 setvect(8,old_int8);
667
668 tcb_state();
669
670 printf("\n Muli_task system teminated \n");
671 }