操作系统实验3-线程间的双向消息通信
来源:互联网 发布:淘宝图片发不出去 编辑:程序博客网 时间:2024/06/15 14:06
线程间的双向消息通信
我们知道,信号量的值初始化为0时可作为同步控制,值为1时可作为互斥控制。在消息通信中,这里假设有两个线程A,B,那双向通信就需要两个信号量来同步消息。
在实验中,我们定义两个同步信号量: semaphore sem1 = {0,NULL}; semaphore sem2 = {0,NULL};
其中,sem1用于A向B发送消息和B向A接收消息,sem2用于B向A发送消息和A向B接收消息。
现在,我们来修改一下模拟两个线程执行内容的函数:
线程1:
void f1() /* 1#线程 */{ long i, j, k; char a[NTEXT]; int len = 0; i = 0; while(++i) { if(i == 5) break; printf("f1 sending!\n"); send("f2", "f1 send message to f2", 21); v(&sem1); // 发送消息后,sem1的value+1使得线程2被主动唤醒执行 p(&sem2); // 要接收消息,先检查sem2的value-1是否>=0,小于0的话将阻塞该线程直到有消息发送过来被主动唤醒 len = receive("f2", a); printf("f1 received %d: %s\n\n", len, a); }}线程2同理:
void f2() /* 2#线程 */{ int i, j, k; int len = 0; char a[NTEXT]; i = 0; while(++i) { if(i == 5) break; p(&sem1); // 要接收消息,先检查sem1的value-1是否>=0,小于0的话将阻塞该线程直到有消息发送过来被主动唤醒 len = receive("f1", a); printf("f2 received %d: %s\n\n", len, a); printf("f2 sending!\n"); send("f1", "f2 send message to f1", 21); v(&sem2); // 发送消息后,sem2的value+1使得线程1被主动唤醒执行 }}
和之前两次实验一样,这里我们也要更改线程的调度函数,我这里是基于优先级调度而非时间片切换调度,注意要初始化默认的优先级值。
代码如下:
int Find(){ int i = 0, index = 0, maxpri = 0; for(i = 1; i < NTCB; i++) { if(tcb[i].state != FINISHED && tcb[i].state != BLOCKED && maxpri < tcb[i].value) { maxpri = tcb[i].value; index = i; } } return index;}
在代码中,还有一些小细节需要修改,比如receive()函数:
int receive(char *sender, char *a){ struct buffer *buff; int i; int size = 0; disable(); for(i = 0; i < NTCB; i++) if(strcmp(sender, tcb[i].name) == 0) break; if(i == NTCB) { printf("error:sender not exist!\n"); enable(); return size; } if(tcb[current].mq == NULL) { p(&tcb[current].sm); return size; } p(&tcb[current].mutex); /* 当前线程的消息缓冲队列资源的互斥操作*/ buff = tcb[current].mq; tcb[current].mq = tcb[current].mq->next; for(i = 0; i < buff->size; i++, a++) /* 输出所接受的内容 */ (*a) = buff->text[i]; *a = '\0'; size = buff->size; v(&tcb[current].mutex); /* 当前线程的消息缓冲队列资源的互斥操作 */ p(&mutexfb); buff->sender = -1; buff->size = 0; strcpy(buff->text, ""); buff->next = NULL; putbuf(buff); v(&mutexfb); v(&sfb); p(&tcb[current].sm); return size;//v(&test); /* 对应于p(&Tcb[current].sm) */}
到此,我们看一下运行结果:
大家最关心的是最后代码了,好的,这就贴上:
#include <stdlib.h>#include <dos.h>#include <stdio.h>#define GET_INDOS 0x34 /* 34H 系统功能调用 */#define GET_CRIT_ERR 0x5d06 /* 5D06H号系统功能调用 */#define BLANK -1#define FINISHED 0 /* 终止 */#define RUNNING 1 /* 执行 */#define READY 2 /* 就绪 */#define BLOCKED 3 /* 阻塞 */#define NTCB 3 /* 系统线程的最大数 */#define TL 10 /* 时间片大小 */#define NBUF 2 /* 消息缓冲区数目 */#define NTEXT 50 /* 文本输出大小 */char far* intdos_ptr = 0;char far* crit_err_ptr = 0;int timecount = 0;int current = -1;typedef unsigned int UINT16;typedef struct/* 信号量 */{ int value; struct TCB* wq;} semaphore;semaphore mutexfb = {1, NULL};semaphore sfb = {2, NULL};semaphore sem1 = {0, NULL};semaphore sem2 = {0, NULL};struct buffer/* 消息缓冲区 */{ int sender; /*消息发送者的标识数 */ int size; /* 消息长度<=NTEXT 个字节 */ char text[NTEXT]; /* 消息正文 */ struct buffer* next; /* 指向下一个消息缓冲区的指针 */} *freebuf;struct TCB /* 线程控制块 */{ unsigned char* stack; /* 堆栈的起始地址 */ unsigned ss; unsigned sp; /* 堆栈段址和堆栈指针 */ char state; /* 进程状态 */ char name[10]; /* 线程的外部标识符 */ int value; /*优先级*/ struct TCB* next; /* 指向控制快指针 */ struct buffer* mq; /* 消息缓冲队列首指针 */ semaphore mutex; /* 互斥信号量 */ semaphore sm; /* 消息缓冲队列计数信号量*/} tcb[NTCB];struct int_regs /* 堆栈现场保护和恢复结构体 */{ unsigned BP, DI, SI, DS, ES, DX, CX, BX, AX, IP, CS, Flags, off, seg;};typedef int(far* codeptr)(void);void interrupt(*old_int8)(void);int DosBusy(void);void InitIndos(void);void InitTcb();void interrupt new_int8(void);void interrupt swtch();void send(char *receiver, char *a, int size);int receive(char *sender, char *a);void p(semaphore *sem);void v(semaphore *sem);int Create(char* name, codeptr code, int stacklen, int prio); /* 创建线程 */void Destroy(int i);void f1() /* 1#线程 */{ long i, j, k; char a[NTEXT]; int len = 0; i = 0; while(++i) { if(i == 5) break; printf("f1 sending!\n"); send("f2", "f1 send message to f2", 21); v(&sem1); p(&sem2); len = receive("f2", a); printf("f1 received %d: %s\n\n", len, a); }}void f2() /* 2#线程 */{ int i, j, k; int len = 0; char a[NTEXT]; i = 0; while(++i) { if(i == 5) break; p(&sem1); len = receive("f1", a); printf("f2 received %d: %s\n\n", len, a); printf("f2 sending!\n"); send("f1", "f2 send message to f1", 21); v(&sem2); }}void InitInDos() /* 取得INDOS标志和严重错误标志地址 */{ union REGS regs; struct SREGS segregs; regs.h.ah = GET_INDOS; /* 使用34H号系统功能调用 */ intdosx(®s, ®s, &segregs); intdos_ptr = MK_FP(segregs.es, regs.x.bx); if(_osmajor < 3) crit_err_ptr = intdos_ptr + 1; /* 严重错误在INDOS后一字节处 */ else if(_osmajor == 3 && _osminor == 0) crit_err_ptr = intdos_ptr - 1; /* 严重错误在INDOS前一字节处 */ else { regs.x.ax = GET_CRIT_ERR; intdosx(®s, ®s, &segregs); crit_err_ptr = MK_FP(segregs.ds, regs.x.si); }}int DosBusy(void) /* 判断DOS是否忙 */{ if(intdos_ptr && crit_err_ptr) return(*intdos_ptr || *crit_err_ptr); /* DOS忙,返回严重错误标志 */ else return(-1); /* DOS不忙 */}void InitTcb() /* 初始化线程 */{ int i; for(i = 0; i < NTCB; i++) { tcb[i].state = BLANK; /* 初始状态标志 */ tcb[i].mq = NULL; tcb[i].mutex.value = 1; tcb[i].mutex.wq = NULL; tcb[i].sm.value = 0; tcb[i].sm.wq = NULL; }}void Destroy(int i){ if(tcb[i].state == RUNNING) { disable(); tcb[i].state = FINISHED; //strcpy(tcb[i].name,NULL); free(tcb[i].stack); tcb[i].ss = 0; tcb[i].sp = 0; enable(); }// return;}void over(){ Destroy(current); swtch();}int Create(char *name, codeptr code, int stacklen, int value){ int i; char *p; struct int_regs *pt; unsigned int *pp; for(i = 1; i < NTCB; i++) { if(tcb[i].state == BLANK || tcb[i].state == FINISHED) break; } if(i == NTCB) return -1; tcb[i].value = value; strcpy(tcb[i].name, name); tcb[i].stack = (p = (unsigned char*)malloc(stacklen)); memset(tcb[i].stack, 0xff, stacklen); p = p + stacklen; *(p - 1) = (FP_SEG(over) & 0xff00) >> 8; *(p - 2) = FP_SEG(over) & 0x00ff; *(p - 3) = (FP_OFF(over) & 0xff00) >> 8; *(p - 4) = FP_OFF(over) & 0x00ff; *(p - 5) = 0x02; *(p - 6) = 0x00; *(p - 7) = (FP_SEG(code) & 0xff00) >> 8; *(p - 8) = FP_SEG(code) & 0x00ff; *(p - 9) = (FP_OFF(code) & 0xff00) >> 8; *(p - 10) = FP_OFF(code) & 0x00ff; *(p - 19) = (_ES & 0xff00) >> 8; *(p - 20) = _ES & 0x00ff; *(p - 21) = (_DS & 0xff00) >> 8; *(p - 22) = _DS & 0x00ff; tcb[i].sp = FP_OFF((UINT16 *)(p - 28)); tcb[i].ss = FP_SEG((UINT16 *)(p - 28)); tcb[i].state = READY; return i;}void tcb_state() /* 线程状态信息 */{ int i; for(i = 0; i < NTCB; i++) if(tcb[i].state != BLANK) { switch(tcb[i].state) { case FINISHED: printf("\ntcb[%d] is FINISHED\n", i); break; case RUNNING: printf("tcb[%d] is RUNNING\n", i); break; case READY: printf("tcb[%d] is READY\n", i); break; case BLOCKED: printf("tcb[%d] is BLOCKED\n", i); break; } }}int all_finished(){ int i; for(i = 1; i < NTCB; i++) if(tcb[i].state == RUNNING || tcb[i].state == BLOCKED || tcb[i].state == READY) return 0; return 1;}int Find(){ int i = 0, index = 0, maxpri = 0; for(i = 1; i < NTCB; i++) { if(tcb[i].state != FINISHED && tcb[i].state != BLOCKED && maxpri < tcb[i].value) { maxpri = tcb[i].value; index = i; } } return index;}void interrupt new_int8(void) /* CPU 调度*/{ int i; (*old_int8)(); /* 指向原来时钟中断处理过程入口的中断处理函数指针 */ timecount++; if(timecount == TL) /* 时间片是否到? */ { if(!DosBusy()) /* DOS是否忙? */ { disable(); tcb[current].ss = _SS; /* 保存现场 */ tcb[current].sp = _SP; if(tcb[current].state == RUNNING) tcb[current].state = READY; i = Find(); if(i < 0) return; _SS = tcb[i].ss; _SP = tcb[i].sp; tcb[i].state = RUNNING; current = i; timecount = 0; /* 重新计时 */ enable(); } else return; } else return;}void interrupt swtch() /* 其他原因CPU调度 */{ int i; if(tcb[current].state != FINISHED && current != 0 && tcb[current].state != BLOCKED) /* 当前线程还没结束 */ return; i = Find(); if(i < 0) return; disable(); tcb[current].ss = _SS; tcb[current].sp = _SP; if(tcb[current].state == RUNNING) tcb[current].state = READY; /* 放入就绪队列中 */ _SS = tcb[i].ss; _SP = tcb[i].sp; /* 保存现场 */ tcb[i].state = RUNNING; current = i; enable();}struct buffer*Initbuf(void){ struct buffer *p, *pt, *pt2; int i; pt2 = pt = (struct buffer*)malloc(sizeof(struct buffer)); pt->sender = -1; pt->size = 0; strcmp(pt->text, ""); pt->next = NULL; for(i = 0; i < NBUF - 1; i++) { p = (struct buffer*)malloc(sizeof(struct buffer)); p->sender = -1; p->size = 0; p->text[NTEXT] = '\0'; p->next = NULL; pt2->next = p; pt2 = p; } return pt;}struct buffer* getbuf(void) /* 从空闲消息缓冲队列队头上取下一缓冲区 */{ struct buffer *buf; buf = freebuf; /* 取得缓冲队列的缓冲区*/ freebuf = freebuf->next; return(buf); /* 返回指向该缓冲区的指针 */}void putbuf(struct buffer *pt){ struct buffer *p = freebuf; while(p->next) p = p->next; p->next = pt; pt->next = NULL;}void block(struct TCB **p) /* 阻塞原语 */{ struct TCB *pp; tcb[current].state = BLOCKED; if((*p) == NULL) *p = &tcb[current]; /* 阻塞队列空,直接放入 */ else { pp = *p; while(pp->next) pp = pp->next; /* 找到阻塞队列最后一个节点 */ pp->next = &tcb[current]; /* 放入阻塞队列 */ } tcb[current].next = NULL; swtch(); /* 重新进行CPU调度 */}void wakeup_first(struct TCB **p) /* 唤醒队首线程 */{ struct TCB *pl; if((*p) == NULL) return; pl = (*p); (*p) = (*p)->next; /* 得到阻塞队列队首线程 */ pl->state = READY; /* 修为就绪状态 */ pl->next = NULL; swtch();}void p(semaphore *sem){ struct TCB **qp; disable(); sem->value = sem->value - 1; if(sem->value < 0) { qp = &(sem->wq); block(qp); } enable();}void v(semaphore*sem){ struct TCB **qp; disable(); qp = &(sem->wq); sem->value = sem->value + 1; if(sem->value >= 0) wakeup_first(qp); enable();}void insert(struct buffer **mq, struct buffer *buff){ /* 将buff所指的缓冲区插到*mq所指的缓冲队列末尾*/ struct buffer *temp; if(buff == NULL) return; /* buff为空 */ buff->next = NULL; if(*mq == NULL) /* *mq为空 则直接插入*/ *mq = buff; else { temp = *mq; while(temp->next) /* 找到队尾 */ temp = temp->next; temp->next = buff; }}void send(char *receiver, char *a, int size){ /* 将地址a开始的size个字节发送给外部标识符为receiver的线程 */ struct buffer *buff; int i, id = -1; disable(); for(i = 0; i < NTCB; i++) /* 找receiver相对应的线程号*/ { if(strcmp(receiver, tcb[i].name) == 0) { id = i; break; } } if(id == -1) /* 没找到 */ { printf("Error:Receiver not exist!\n"); enable(); return; } p(&sfb); /* 空闲缓冲队列数量的互斥操作 */ p(&mutexfb); /* 空闲缓冲队列资源的互斥操作 */ buff = getbuf(); /* 获得一缓冲区 */ v(&mutexfb); buff->sender = current; buff->size = size; buff->next = NULL; for(i = 0; i < buff->size; i++, a++) /* 写入缓冲队列 */ buff->text[i] = *a; p(&tcb[id].mutex); /* 相应线程的消息缓冲队列互斥操作 */ insert(&(tcb[id].mq), buff); /* buff所指的缓冲区插到相应线程的消息缓冲队列末尾 */ v(&tcb[id].mutex); v(&tcb[id].sm); /* 对应于p(&sfb),线程的消息缓冲队列数量的互斥操作 */ enable();}int receive(char *sender, char *a){ struct buffer *buff; int i; int size = 0; disable(); for(i = 0; i < NTCB; i++) if(strcmp(sender, tcb[i].name) == 0) break; if(i == NTCB) { printf("error:sender not exist!\n"); enable(); return size; } if(tcb[current].mq == NULL) { p(&tcb[current].sm); return size; } p(&tcb[current].mutex); /* 当前线程的消息缓冲队列资源的互斥操作*/ buff = tcb[current].mq; tcb[current].mq = tcb[current].mq->next; for(i = 0; i < buff->size; i++, a++) /* 输出所接受的内容 */ (*a) = buff->text[i]; *a = '\0'; size = buff->size; v(&tcb[current].mutex); /* 当前线程的消息缓冲队列资源的互斥操作 */ p(&mutexfb); buff->sender = -1; buff->size = 0; strcpy(buff->text, ""); buff->next = NULL; putbuf(buff); v(&mutexfb); v(&sfb); p(&tcb[current].sm); return size;//v(&test); /* 对应于p(&Tcb[current].sm) */}void main(){ long i, j, k; InitInDos(); InitTcb(); freebuf = Initbuf(); old_int8 = getvect(8); strcpy(tcb[0].name, "main"); tcb[0].state = RUNNING; tcb[0].value = 0; current = 0; Create("f1", (codeptr)f1, 1024, 5); Create("f2", (codeptr)f2, 1024, 6); tcb_state(); setvect(8, new_int8);// swtch(); while(!all_finished()); tcb[0].name[0] = '\0'; tcb[0].state = FINISHED; setvect(8, old_int8); tcb_state(); printf("\n Muli_task system teminated \n");}
0 0
- 操作系统实验3-线程间的双向消息通信
- android 线程间的消息通信
- 操作系统--线程和进程/线程管道通信实验
- 操作系统---进程/线程 间通信
- 操作系统---进程/线程 间通信
- 操作系统:进程的软中断通信实验
- 操作系统:进程的管道通信实验
- Windows 线程间消息通信
- 操作系统实验-进程通信
- 操作系统 进程通信实验
- 线程间通信的消息机制的Message和Handler
- java线程间通信[实现不同线程之间的消息传递(通信),生产者和消费者模型]
- VC++基础 使用自定义消息实现线程间的通信
- android开发之线程间通信(消息的使用)
- Android的消息循环——线程间通信
- 用消息的方式实现线程通信
- 线程间通信之Handler小实验
- 自定义消息实现线程间通信
- uvaoj 1586-molar mass
- arm处理中断流程
- Java多线程基础:进程和线程之由来
- 360校园招聘笔试题
- leetcode scramble-string
- 操作系统实验3-线程间的双向消息通信
- 得到所有Activity和Service
- windows下搭建配置svn服务器以及svn客户端的使用
- 判断链表是否存在环
- 研究生之路之算法导论
- 使用Java获得电脑各个分区下的所有文件名和路径
- 每日一算法之Fibonacci数
- QT容器类
- 【 题集 】 RPG专场练习赛