www.pudn.com > readerwriter1.rar > readerwriter1.c
/* readerwriter1.c 读者-写者问题模拟, 2004.12.6 优先级: 读者优先 流程: 1.读取输入参数文件 2.创建互斥量和信号量 3.创建线程(挂起状态) 4.恢复线程运行 5.等待所有线程运行结束, 退出 说明: 1.各读/写者到达时间不同, 用长短不同的睡眠时间表示; 2.各读/写者访问临界资源的持续时间长短不一, 随机生成, 用不同的睡眠时间表示; 执行方法: C:\>readerwriter1 < parm.txt */ #include#include #include #define MAX_NUM 100 /* 读者+写者的最大数量 */ #define LINESIZE 80 struct rwparm { int seq; /* 读者/写者序号 */ int rwtype; /* 读者/写者类型: R/W */ float arvtime; /* 读者/写者到达时间 */ }rwparms[MAX_NUM]; #define FIRSTARVTIME 0 /* 最早到达时间: 0s */ #define LASTARVTIME 300 /* 最迟到达时间: 300s */ #define MINDURATION 2000 /* 读者/写者访问临界资源的最小持续时间: 2000ms */ #define MAXDURATION 10000 /* 读者/写者访问临界资源的最大持续时间: 10000ms */ int rcnt = 0; /* 读者数量 */ HANDLE hMutex; HANDLE hWSem; clock_t curclk; /* 用进程运行时间表示共享资源 */ DWORD WINAPI reader(LPVOID lpParm); DWORD WINAPI writer(LPVOID lpParm); int getparm(HANDLE *hThread); int main(int argc, char *argv[]) { HANDLE hThread[MAX_NUM]; DWORD dwId; int rwnum; /* 记录总的读者+写者数量 */ int i; /* 1.读取输入参数 */ rwnum = getparm(hThread); if(rwnum == 0) { printf("No parameters input.\n"); exit(0); } /* 初始化 */ srand(time(NULL)); curclk = clock(); /* 2.创建互斥量和信号量 */ hMutex = CreateMutex(NULL, FALSE, NULL); if(hMutex == NULL) { printf("Error create mutex.\n"); exit(-1); } hWSem = CreateSemaphore(NULL, 1, 1, NULL); if(hWSem == NULL) { printf("Error create wsem.\n"); exit(-1); } /* 3.创建线程(挂起状态) */ for(i = 0; i < rwnum; i++) { if(rwparms[i].rwtype == 'R') hThread[i] = CreateThread(NULL, 0, reader, &rwparms[i], CREATE_SUSPENDED, &dwId); else hThread[i] = CreateThread(NULL, 0, writer, &rwparms[i], CREATE_SUSPENDED, &dwId); } /* 4.恢复线程运行 */ printf("Starting at %d...\n", curclk); for(i = 0; i < rwnum; i++) ResumeThread(hThread[i]); /* 5.等待所有线程运行结束 */ WaitForMultipleObjects(rwnum, hThread, TRUE, INFINITE); printf("All done.\n"); } /* 读者锁. seq为该读者序号. */ void rlock(int seq) { if(WaitForSingleObject(hMutex, INFINITE) != WAIT_OBJECT_0) { printf("!!!Reader(%d): Wait mutex failed.\n", seq); exit(-1); } if(++rcnt == 1) { /* 如果是第1个读者, 要对hWSem加锁, 防止写者进入 */ if(WaitForSingleObject(hWSem, INFINITE) != WAIT_OBJECT_0) { ReleaseMutex(hMutex); printf("!!!Reader(%d): Wait wsem failed.\n", seq); exit(-1); } } ReleaseMutex(hMutex); } /* 读者解锁 */ void runlock(int seq) { if(WaitForSingleObject(hMutex, INFINITE) != WAIT_OBJECT_0) { printf("!!!Reader(%d): Wait mutex failed.\n", seq); exit(-1); } if(--rcnt==0) { /* 如果是最后一个读者, 要对hWSem解锁, 允许写者进入 */ ReleaseSemaphore(hWSem, 1, NULL); } ReleaseMutex(hMutex); } DWORD WINAPI reader(LPVOID lpParm) { int i, total; int durtime; struct rwparm * rwsp; rwsp = (struct rwparm *)lpParm; /* lpParm参数为rwparm结构指针 */ /* 生成持续访问时间 */ durtime = (rand() % (MAXDURATION + 1 - MINDURATION)) + MINDURATION; /* 先按照到达时间要求睡眠 */ Sleep(rwsp->arvtime * 1000); printf("@ Reader(%d) coming at %.3f\n", rwsp->seq, rwsp->arvtime); /* 读者加锁 */ rlock(rwsp->seq); printf("> Reader(%d) enters CS at %.3f (CS=%d)\n", \ rwsp->seq, (float)clock()/CLOCKS_PER_SEC, curclk); fflush(stdout); Sleep(durtime); printf("< Reader(%d) leaves CS at %.3f (CS=%d)\n", \ rwsp->seq, (float)clock()/CLOCKS_PER_SEC, curclk); fflush(stdout); runlock(rwsp->seq); } /* 写者锁 */ void wlock(int seq) { if(WaitForSingleObject(hWSem, INFINITE) != WAIT_OBJECT_0) { printf("!!!Writer(%d): Wait wsem failed.\n", seq); exit(-1); } } /* 写者解锁 */ void wunlock() { ReleaseSemaphore(hWSem, 1, NULL); } DWORD WINAPI writer(LPVOID lpParm) { int durtime; clock_t oldclk; struct rwparm * rwsp; rwsp = (struct rwparm *)lpParm; durtime = (rand() % (MAXDURATION + 1 - MINDURATION)) + MINDURATION; Sleep(rwsp->arvtime * 1000); printf("Writer(%d) coming at %.3f\n", rwsp->seq, rwsp->arvtime); wlock(rwsp->seq); printf("=Writer(%d) enters CS at %.3f\n", rwsp->seq, (float)clock()/CLOCKS_PER_SEC); fflush(stdout); Sleep(durtime); oldclk = curclk; curclk = clock(); printf("=Writer(%d) leaves CS at %.3f(update CS from %d to %d)\n", \ rwsp->seq, (float)clock()/CLOCKS_PER_SEC, oldclk, curclk); fflush(stdout); wunlock(); } /* 输入参数函数. hThread为一句柄数组指针. 返回读者+写者数. */ int getparm(HANDLE *hThread) { int i,j; char lnbuf[LINESIZE+1]; /* 1.输入参数 注意参数输入方式: scanf不会读取行末回车符, 因此第二次scanf时, 读入的第一个 字符变量将是 '\n'. 故采取先输入一行, 再从行缓冲区中读入参数的方法. */ printf("Input parameters for readers and writers: \n"); i = 0; while( fgets(lnbuf, LINESIZE, stdin) != NULL) { printf(lnbuf); j = sscanf(lnbuf, "%c %f", &(rwparms[i].rwtype), &(rwparms[i].arvtime)); // 如果一行中参数个数超出或小于2个, 无效 if( j != 2 ) { printf("Input 2 parameters in one line.\n"); continue; } /* 参数有效性检查 */ if ( (toupper(rwparms[i].rwtype) != 'R') && (toupper(rwparms[i].rwtype) != 'W') ) { printf("Invalid thread type: %c(%02X)\n", \ rwparms[i].rwtype,rwparms[i].rwtype); continue; } if( (rwparms[i].arvtime < FIRSTARVTIME) || (rwparms[i].arvtime > LASTARVTIME) ) { printf("Invalid arriving time: %.2f\n", rwparms[i].arvtime); continue; } rwparms[i].rwtype = toupper(rwparms[i].rwtype); rwparms[i].seq = i; // printf("%c, %.2f\n", toupper(rwparms[i].rwtype), rwparms[i].arvtime); i++; if(i >= MAX_NUM) break; } return i; }