操作系统实验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(&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].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