實驗分兩部分,第一部分,實作互斥
思路很簡單,利用信号量,将其值初始化為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(®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].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(®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].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");
}
好了,打完收工。