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; 
}