操作系统实验2-互斥与同步

来源:互联网 发布:聚翔网络 编辑:程序博客网 时间:2024/05/01 08:37

实验分两部分,第一部分,实现互斥

     思路很简单,利用信号量,将其值初始化为1,semaphore resource = {1,NULL};
获取资源时做P()操作,释放资源使用权时做V()操作。

所以

void p1( ){    long i, j, k;    p(&semlock); //获取资源使用权,如果不能获取,会被放到信号量队列中等待资源可用被唤醒    //中间过程相当于是在使用这个资源(模拟)    for(i=0; i<40; i++)    {        putchar('a');        for(j=0; j<1000; j++)            for(k=0; k<20000; k++);    }    v(&semlock); //释放资源,信号量值加1,队列中第一个线程会被唤醒(如果队列不为空)}void p2( ){    long i, j, k;    p(&semlock);  //同p1()    for(i=0; i<20; i++)    {        putchar('b');        for(j=0; j<1000; j++)            for(k=0; k<20000; k++);    }    v(&semlock);}
另外,我们要更改Find()调度程序,找到没有被阻塞的线程来调度

int Find(){    int i,j;    for(i = 1; i < NTCB; i++)    {        if(tcb[i].state != FINISHED && tcb[i].state != BLOCKED) return i;    }    return 0;}
到这里,互斥锁就完成了。上最终代码:

#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 10        /* 消息缓冲区数目 */#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;int critical = 0; //semaphore semlock = {1,NULL};struct TCB            /* 线程控制块  */{    unsigned char* stack;          /* 堆栈的起始地址  */    unsigned ss;    unsigned sp;            /* 堆栈段址和堆栈指针 */    char state;             /* 进程状态   */    char name[10];          /* 线程的外部标识符  */    int value;             /*优先级*/    struct TCB* next;       /* 指向控制快指针  */    semaphore mutex;        /* 互斥信号量   */} 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 p(semaphore *sem);void v(semaphore *sem);int Create(char* name,codeptr code,int stacklen,int prio);  /* 创建线程 */void Destroy(int i);void p1( ){    long i, j, k;    p(&semlock);    for(i=0; i<40; i++)    {        putchar('a');        for(j=0; j<1000; j++)            for(k=0; k<20000; k++);    }    v(&semlock);}void p2( ){    long i, j, k;    p(&semlock);    for(i=0; i<20; i++)    {        putchar('b');        for(j=0; j<1000; j++)            for(k=0; k<20000; k++);    }    v(&semlock);}void InitInDos()      /* 取得INDOS标志和严重错误标志地址 */{    union REGS regs;    struct SREGS segregs;    regs.h.ah=GET_INDOS;      /* 使用34H号系统功能调用 */    intdosx(&regs,&regs,&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(&regs,&regs,&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].mutex.value=1;        tcb[i].mutex.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;    pt=(struct int_regs*)p;    pt--;    pt->Flags=0x200;    pt->CS=FP_SEG(code);    pt->IP=FP_OFF(code);    pt->off=FP_OFF(over);    pt->seg=FP_SEG(over);    pt->DS=_DS;    pt->ES=_ES;    tcb[i].sp=FP_OFF(pt);    tcb[i].ss=FP_SEG(pt);    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,j;    for(i = 1; i < NTCB; i++)    {        if(tcb[i].state != FINISHED && tcb[i].state != BLOCKED) return i;    }    return 0;}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            &¤t!=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();}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;}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 main(){    long i, j, k;    InitInDos();    InitTcb();    old_int8=getvect(8);    strcpy(tcb[0].name,"main");    tcb[0].state=RUNNING;    tcb[0].value=0;    current=0;    Create("p1",(codeptr)p1,1024,5);    Create("p2",(codeptr)p2,1024,5);    disable();    setvect(8, new_int8);    enable();    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");}



第二部分,同步问题,我们用最经典的生产者消费者来说明


首先,定义临界资源访问信号里:semaphore resource = {0,NULL};,注意,值初始化为0;

接下来,生产者与消费者代码实现:

void p1( )        // 生产者{    long i, j, k;    for(i=0; i<40; i++)    {        putchar('a');        for(j=0; j<1000; j++)            for(k=0; k<20000; k++);    } // 前面的过程就是生产者一直在生产的过程,现在生产完成了,v操作通知消费者消费咯    v(&resource);}void p2( )        //消费者{    long i, j, k;    p(&resource); //看看有没有可用的资源来消费,若没有,则被放到信号里resource的队列中,直至资源可用被唤醒    // 下面就是消费者消费过程(模拟,别当真)    for(i=0; i<20; i++)    {        putchar('b');        for(j=0; j<1000; j++)            for(k=0; k<20000; k++);    }}
好,上最终代码:

#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 10        /* 消息缓冲区数目 */#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 resource = {0,NULL};  //struct TCB            /* 线程控制块  */{    unsigned char* stack;          /* 堆栈的起始地址  */    unsigned ss;    unsigned sp;            /* 堆栈段址和堆栈指针 */    char state;             /* 进程状态   */    char name[10];          /* 线程的外部标识符  */    int value;             /*优先级*/    struct TCB* next;       /* 指向控制快指针  */    semaphore mutex;        /* 互斥信号量   */} 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 p(semaphore *sem);void v(semaphore *sem);int Create(char* name,codeptr code,int stacklen,int prio);  /* 创建线程 */void Destroy(int i);void p1( )        // 生产者{    long i, j, k;    for(i=0; i<40; i++)    {        putchar('a');        for(j=0; j<1000; j++)            for(k=0; k<20000; k++);    }    v(&resource);}void p2( )        //消费者{    long i, j, k;    p(&resource);    for(i=0; i<20; i++)    {        putchar('b');        for(j=0; j<1000; j++)            for(k=0; k<20000; k++);    }}void InitInDos()      /* 取得INDOS标志和严重错误标志地址 */{    union REGS regs;    struct SREGS segregs;    regs.h.ah=GET_INDOS;      /* 使用34H号系统功能调用 */    intdosx(&regs,&regs,&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(&regs,&regs,&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].mutex.value=1;        tcb[i].mutex.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;    pt=(struct int_regs*)p;    pt--;    pt->Flags=0x200;    pt->CS=FP_SEG(code);    pt->IP=FP_OFF(code);    pt->off=FP_OFF(over);    pt->seg=FP_SEG(over);    pt->DS=_DS;    pt->ES=_ES;    tcb[i].sp=FP_OFF(pt);    tcb[i].ss=FP_SEG(pt);    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,j;    i=current;    while(tcb[i=((i+1)%NTCB)].state!=READY ||i==current);    return i;}/*int Find(){   int i,index,max_pri;   i = index = max_pri = 0;   for( ; i < NTCB; i++)   {       if(tcb[i].state != FINISHED && tcb[i].state != BLOCKED && tcb[i].value > max_pri)       {           index = i;           max_pri = tcb[i].value;       }   }   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            &¤t!=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();}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;}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 main(){    long i, j, k;    InitInDos();    InitTcb();    old_int8=getvect(8);    strcpy(tcb[0].name,"main");    tcb[0].state=RUNNING;    tcb[0].value=0;    current=0;    Create("p1",(codeptr)p1,1024,5);    Create("p2",(codeptr)p2,1024,5);    disable();    setvect(8, new_int8);    enable();    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
原创粉丝点击