操作系统课程设计 消息缓冲队列通信
消息缓冲队列通信机制其基本思想是根据“生产者——消费者”原理,利用内存中公用消息缓冲区实现进程间的信息交换。
在这种通信机制中,首先需要在内存中开辟若干空闲消息缓冲区,用以存放要通信的消息。每当一个进程需要向另一个进程发送消息时,便向系统申请一个空闲消息缓冲区,并把已准备好的消息复制到该缓冲区,然后把该消息缓冲区插入到接收进程的消息队列中,最后通知接收进程。接收进程接收到发送进程发来的通知后,从本进程的消息队列中摘下一消息缓冲区,取出其中的信息,然后把消息缓冲区作为空闲消息缓冲区归还给系统。系统负责管理公用消息缓冲区以及消息的传递。
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 }