《杭电操作系统课程设计.doc》由会员分享,可在线阅读,更多相关《杭电操作系统课程设计.doc(18页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、#include #include #include #include #define GET_INDOS 0x34#define GET_CRIT_ERR 0x5d06#define FINISHED 0 / 表示线程处于终止态或TCB是空白状态#define RUNNING 1 / 表示线程处于运行态#define READY 2 / 表示线程处于就绪态#define BLOCKED 3 / 表示线程处于阻塞态#define NTCB 5 / 表示系统允许线程的最大数#define NTEXT 20 / 消息的最大字节数#define NBUF 5 / 消息缓冲区的数目char far *
2、indos_ptr = 0; / INDOS标志的地址char far *crit_err_ptr = 0; / 严重错误标志的地址int current = 0; / 当前线程的内部标识符int timecount = 0; / 从调度至今运行的时间int TL = 1; / 时间片大小int sum;int buf5;int in, out;/* 记录型信号量 */typedef struct int value; / 信号量的值,表示空闲资源总数 struct TCB *wq; / 线程阻塞队列队首指针semaphore;/* 线程控制块 */struct TCB unsigned ch
3、ar *stack; / 线程堆栈的起始地址 unsigned ss; / 堆栈段址 unsigned sp; / 堆栈指针 char state; / 线程状态,取值可以是FINISHED、RUNNING、READY、BLOCKED char name10; / 线程的外部标识符 struct TCB *next; / 指向下一个线程的指针 struct buffer *mq; / 接收线程的消息队列队首指针 semaphore mutex; / 接收线程的消息队列的互斥信号量 semaphore sm; / 接收线程的消息队列的计数信号量,用于实现同步tcbNTCB;/* 线程的私有堆栈,
4、保存现场信息 */struct int_regs unsigned BP, DI, SI, DS, ES, DX, CX, BX, AX, IP, CS, Flags, off, seg;/* 消息缓冲区 */struct buffer int sender; / 消息发送者的内部标识 int size; / 消息长度=NTEXT个字节 char textNTEXT; / 消息正文 struct buffer *next; / 指向下一个消息缓冲区的指针*freebuf; / 空闲消息缓冲队列semaphore mutexfb = 1, NULL; / 空闲消息缓冲队列的互斥信号量semaph
5、ore sfb = NBUF, NULL; / 空闲消息缓冲队列的计数信号量semaphore mutex = 1,NULL;semaphore empty = 5, NULL;semaphore full = 0, NULL;typedef int (far *codeptr)(); / 定义一个函数指针类型void interrupt (*old_int8)(); / 定义一个函数指针old_int8void initDos(); / 初始化DOS,获得INDOS标志的地址和严重错误标志的地址void initTcb(); / 初始化TCBint DosBusy(); / 判断当前DOS是
6、否忙碌int create(char *name, codeptr code, int stackLen); / 线程创立void destroy(int id); / 线程撤销void over(); / 线程自动撤销void interrupt new_int8(); / 时间片到时引起的CPU调度void interrupt my_swtch(); / 其他原因引起的CPU调度void block(struct TCB *qp); / 插入线程到阻塞队列void wakeup_first(struct TCB *qp); / 唤醒阻塞队列队首进程void P(semaphore *sem
7、); / 对信号量的P操作void V(semaphore *sem); / 对信号量的V操作void initBuf(); / 初始化消息缓冲区struct buffer *getbuf(); / 获取消息空闲缓冲区void putbuf(struct buffer *buff); / 插入空闲消息缓冲队列void insert(struct buffer *mq, struct buffer *buff); / 插入消息缓冲区到消息队列struct buffer *remov(struct buffer *mq, int sender); / 获取消息缓冲区void send(char *
8、receiver, char *a, int size); / 发送原语int receive(char *sender, char *b); / 接收原语int find(); / 寻找READY状态线程的内部标识符void tcb_state(); / 线程状态信息int finished(); / 检查除0#线程外的所有其他线程是否都已运行/* 初始化DOS,获得INDOS标志的地址和严重错误标志的地址 */void initDos() union REGS regs; struct SREGS segregs; / 获得 INDOS 标志的地址 regs.h.ah = GET_INDO
9、S; intdosx(®s, ®s, &segregs); / intdosx():Turbo C的库函数,其功能是调用DOS的INT21H中断 indos_ptr = MK_FP(segregs.es, regs.x.bx); / MK_FP():不是一个函数,只是一个宏。其功能是做段基址加上偏移地址的运算,也就是取实际地址。 / 获得严重错误标志的地址,代码中用到的_osmajor、_osminor是Turbo C的全程变量,其中前者为DOS版本号的主要局部,后者为版本号的次要局部。 if(_osmajor 3) crit_err_ptr = indos_ptr + 1; /
10、严重错误在INDOS后一字节处 else if(_osmajor = 3 & _osminor = 0) crit_err_ptr = indos_ptr - 1; / 严重错误在INDOS前一字节处 else regs.x.ax = GET_CRIT_ERR; intdosx(®s, ®s, &segregs); crit_err_ptr = MK_FP(segregs.ds, regs.x.si); /* 初始化TCB */void initTcb() int id; for(id = 0; id NTCB; id+) tcbid.stack = NULL; tcbid.sta
11、te = FINISHED; tcbid.name0 = 0; tcbid.next = NULL; tcbid.mq = NULL; tcbid.mutex.value = 1; tcbid.mutex.wq = NULL; tcbid.sm.value = 0; tcbid.sm.wq = NULL; /* 判断当前DOS是否忙碌 */int DosBusy() if(indos_ptr & crit_err_ptr) return (*indos_ptr | *crit_err_ptr); / 返回值是1,表示dos忙;返回值是0,表示dos不忙 else return -1; / 还没
12、有调用initDos()/* 线程创立 */int create(char *name, codeptr code, int stackLen) int id; struct int_regs far *regs; disable(); / 关中断 for(id = 1; id DS = _DS; regs-ES = _ES; regs-IP = FP_OFF(code); regs-CS = FP_SEG(code); regs-Flags = 0x200; regs-off = FP_OFF(over); regs-seg = FP_SEG(over); printf(n * 线程%d %
13、s 已创立 *n, id, tcbid.name); enable(); / 开中断 return id;/* 线程撤销 */void destroy(int id) disable(); / 关中断 / 释放私有堆栈空间,清空TCB信息 free(tcbid.stack); tcbid.stack = NULL; tcbid.state = FINISHED; tcbid.name0 = 0; tcbid.next = NULL; tcbid.mq = NULL; tcbid.mutex.value = 1; tcbid.mutex.wq = NULL; tcbid.sm.value = 0
14、; tcbid.sm.wq = NULL; printf(n * 线程%d %s 已撤销 *n, id, tcbid.name); enable(); / 开中断/* 用于自动撤销线程 */void over() destroy(current); / 撤销当前线程 my_swtch(); / CPU调度/* 时间片到时引起的CPU调度 */void interrupt new_int8() (*old_int8)(); / 调用原来的时钟中断效劳程序 timecount+; / 计时 if(timecount TL | DosBusy() / 时间片未到或DOS正忙 return; my_s
15、wtch(); / 调用my_swtch()进行重新调度/* 其他原因引起的CPU调度 */void interrupt my_swtch() int id; disable(); / 关中断 / 保存现行堆栈的段址和栈顶供下次切换时用 tcbcurrent.ss = _SS; tcbcurrent.sp = _SP; if(tcbcurrent.state = RUNNING) tcbcurrent.state = READY; id = find(); if(id next != NULL) tcbp = tcbp-next; tcbp-next = &tcbcurrent; tcbcur
16、rent.next = NULL; my_swtch(); / CPU调度/* 唤醒阻塞队列队首进程 */void wakeup_first(struct TCB *qp) struct TCB *tcbp; if(*qp) = NULL) return; tcbp = (*qp); (*qp )= (*qp)-next; / 阻塞队列队首指向下一个线程 tcbp-state = READY; tcbp-next = NULL;/* 对信号量的P操作 */void P(semaphore *sem) struct TCB *qp; disable(); / 关中断 sem-value-; /
17、空闲资源数减1 if(sem-value wq); block(qp); / 插入线程到阻塞队列 enable(); / 开中断/* 对信号量的V操作 */void V(semaphore *sem) struct TCB *qp; disable(); / 关中断 sem-value+; / 空闲资源数加1 if(sem-value wq); wakeup_first(qp); / 唤醒阻塞队列队首进程 enable(); / 开中断/* 初始化消息缓冲区 */void initBuf() struct buffer *bufp, *buff; int i; buff = (struct b
18、uffer *)malloc(sizeof(struct buffer); buff-sender = -1; buff-size = 0; buff-text0 = 0; freebuf = bufp = buff; for(i = 1; i sender = -1; buff-size = 0; buff-text0 = 0; bufp-next = buff; bufp = buff; bufp-next = NULL;/* 获取空闲消息缓冲区 */struct buffer *getbuf() struct buffer *buff; buff = freebuf; freebuf =
19、 freebuf-next; / 空闲消息缓冲队列队首指针指向下一个空闲缓冲区 return buff;/* 插入空闲消息缓冲队列 */void putbuf(struct buffer *buff) struct buffer *bufp = freebuf; if(freebuf = NULL) / 假设空闲消息队列为空,队首指向当前消息缓冲区 freebuf = buff; else / 否那么插入队尾 while(bufp-next != NULL) bufp = bufp-next; bufp-next = buff; buff-next = NULL;/* 插入消息缓冲区到消息队列
20、 */void insert(struct buffer *mq, struct buffer *buff) struct buffer *bufp; if(buff = NULL) return; if(*mq) = NULL) / 假设消息队列为空,队首即为当前消息缓冲区 (*mq) = buff; else / 否那么插入队尾 bufp = (*mq); while(bufp-next != NULL) bufp = bufp-next; bufp-next = buff; buff-next = NULL;/* 从消息队列获取消息缓冲区 */struct buffer *remov(s
21、truct buffer *mq, int sender) struct buffer *bufp, *buff; bufp = (*mq); / 假设消息队列队首是sender发送的消息,那么取出该消息缓冲区 if(bufp-sender = sender) buff = bufp; (*mq) = buff-next; buff-next = NULL; return buff; / 寻找发送者为sender的消息缓冲区 while(bufp-next != NULL & bufp-next-sender != sender) bufp = bufp-next; / 假设找不到,那么返回N
22、ULL if(bufp-next = NULL) return NULL; buff = bufp-next; bufp-next = buff-next; buff-next = NULL; return buff;/* 发送原语 */void send(char *receiver, char *a, int size) struct buffer *buff; int i, id; disable(); / 关中断 / 寻找接受者线程 for(id = 0; id sender = current; buff-size = size; for(i = 0; i size; i+, a+)
23、 buff-texti = *a; / 将消息缓冲区插入到接收者线程的消息队列末尾 P(&tcbid.mutex); insert(&(tcbid.mq), buff); V(&tcbid.mutex); V(&tcbid.sm); enable(); / 开中断/* 接收原语 */int receive(char *sender, char *b) struct buffer *buff; int i, id, size; disable(); / 关中断 / 寻找发送者线程 for(id = 0; id size; for(i = 0; i size; i+, b+) *b = buff-
24、texti; buff-sender = -1; buff-size = 0; buff-text0 = 0; / 插入空闲消息缓冲队列 P(&mutexfb); putbuf(buff); V(&mutexfb); V(&sfb); enable(); / 开中断 return size;/* 寻找READY状态线程的内部标识符 */int find() int id; for(id = current + 1; id NTCB; id+) if(tcbid.state = READY) return id; for(id = 0; id current; id+) if(tcbid.sta
25、te = READY) return id; return -1;/* 线程状态信息 */void tcb_state() int id; printf(n * 当前线程状态 *n); for(id = 0; id NTCB; id+) printf(线程%d %9s 状态为 , id, tcbid.name); switch(tcbid.state) case FINISHED: puts(FINISHED); break; case RUNNING: puts(RUNNING); break; case READY: puts(READY); break; case BLOCKED: pu
26、ts(BLOCKED); break; /* 检查除0#线程外的所有其他线程是否都已运行完 */int finished() int id; for(id = 1; id NTCB; id+) if(tcbid.state != FINISHED) return 0; return 1;/* 不断输出a,共50个 */void f1() int i, j, k; for(i = 0; i 50; i+) putchar(a); / 延时 for(j = 0; j 1000; j+) for(k = 0; k 1000; k+); /* 不断输出b,共50个 */void f2() long i
27、, j, k; for(i = 0; i 30; i+) putchar(b); / 延时 for(j = 0; j 1000; j+) for(k = 0; k 1000; k+); /* 不断对sum加1,共50次,与f4互斥 */void f3() int i; int tmp; for(i = 0; i 50; i+) P(&mutex); tmp = sum; delay(5); / 暂停5毫秒 tmp+; sum = tmp; V(&mutex); /* 不断对sum加1,共50次,与f3互斥 */void f4() int i; int tmp; for(i = 0; i 50;
28、 i+) P(&mutex); tmp = sum; delay(10); / 暂停10毫秒 tmp+; sum = tmp; V(&mutex); /* 不断计算1至50的平方,并将结果放入buf中 */void producer() int i; int tmp; for(i = 1; i = 50; i+) tmp = i * i; P(&empty); P(&mutex); bufin = tmp; in = (in + 1) % 5; V(&mutex); V(&full); /* 不断从缓冲中取出结果,并打印出来 */void consumer() int i; int tmp;
29、for(i = 1; i = 50; i+) P(&full); P(&mutex); tmp = bufout; out = (out + 1) % 5; V(&mutex); V(&empty); printf(%dn, tmp); /* 不断向receiver发送消息,共10条 */void sender() int i; char message10 = message; for(i = 0; i 10; i+) message7 = i + 0; message8 = 0; send(receiver, message, strlen(message); printf(消息 %s 已
30、发送n, message); receive(receiver, message); if(message0 = O & message1 = K) printf(所有消息已被接收,通信成功); else printf(消息未被完全接收,通信失败);/* 不断接受从sender发过来的消息 */void receiver() int i; int size; char message10; for(i = 0; i 10; i+) while(size = receive(sender, message) = 0); messagesize = 0; printf(消息 %s 已接收n, me
31、ssage); strcpy(message, OK); send(sender, message, strlen(message); / 发送确认消息int main() int select = -1; initDos(); / 初始化DOS initTcb(); / 初始化TCB initBuf(); / 初始化freebuf old_int8 = getvect(8); / 获取系统原来的时钟中断效劳程序的入口地址 / 创立0#线程 strcpy(tcb0.name, main); tcb0.state = RUNNING; current = 0; while(select) clrscr(); printf(nnnttt 欢送使用多任务系统n); printf(nt*n); printf(t* 1.实现线程的并发执行,可设置时间片大小 *n); printf(t* 2.实现线程对同一资源的互斥访问 *n); printf(t* 3.实现生产者和消费者同步问题 *n); print
限制150内