操原上機(二) 模擬實現“生產者-消費者”問題

實驗內容

在 windows 環境下,利用高級語言編程環境(限定爲 VS 環境或 VC 環境) 調用 CreateThread 函數和相關的同步函數,模擬實現“生產者-消費者”問題。

實驗過程

首先,先寫個生成隨機數的函數,代碼如下:

int random(void){
	int a=time (NULL);
	srand(a);
	return rand()%1000;
}

然後,是生產者的功能函數,主要代碼如下:

if(id == 1)	number = random()+1000;
		else number = random()+2000;
Buffer[rear]=number;
		printf("生產者%d生產Buffer[%d],%d\n",id,rear,Buffer[rear]);
rear = (rear+1)%N;
Sleep(600);

之後,需要加入pv操作以及臨界區。這也是本題的難點所在。下面介紹windows環境是如何實現這些操作的。

臨界區

Windows有專門的臨界區對象。其應用也非常簡單。如下:

CRITICAL_SECTION cs;	//聲明臨界區對象
InitializeCriticalSection(&cs);		//初始化臨界區對象 
EnterCriticalSection(&cs);	//進入臨界區
LeaveCriticalSection(&cs);	//離開臨界區

信號量機制

Windows通過信號量機制來實現p操作和v操作。其應用函數如下:

HANDLE full =NULL;	//聲明
full = CreateSemaphore(NULL ,0 ,N,"full");	//創建
CloseHandle(full); 	//關閉
HANDLE full =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"full");	//打開
WaitForSingleObject(full,INFINITE); 	//p操作
ReleaseSemaphore(empty,1,NULL);	//v操作

在這些函數中
CreateSemaphore(NULL ,0 ,N,“full”)函數的第二個參數是信號量的初始值,應大於等於0;第三個參數爲信號量的最大值,第四個參數爲信號量的名稱(可用於在其他地方打開該信號量)。
ReleaseSemaphore(empty,1,NULL)函數的第二個參數代表釋放之後信號量的值加n。

瞭解了windows的臨界區對象和信號量機制之後,我們就可以理解生產者功能函數加入這兩者之後的代碼了:

DWORD WINAPI Producer(LPVOID lpParam){
	int number;
	int id = ++i;
	HANDLE full =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"full");
	HANDLE empty =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"empty");
	while(1){
		if(id == 1)	number = random()+1000;
		else number = random()+2000;
		//p(empty)
		WaitForSingleObject(empty,INFINITE); 
		EnterCriticalSection(&cs);
		Buffer[rear]=number;
		printf("生產者%d生產Buffer[%d],%d\n",id,rear,Buffer[rear]);
		flag++;
		if(!flag){
			fp=fopen("C:\\Users\\HP\\Desktop\\記錄.txt","w");
			if(fp==NULL){
				printf("can not load file!");
				exit(0); 
			}
		}
		fprintf(fp,"生產者%d生產Buffer[%d],%d\n",id,rear,Buffer[rear]);
	    rear = (rear+1)%N;
		LeaveCriticalSection(&cs);
		//v(full)
		ReleaseSemaphore(full,1,NULL);
		Sleep(600);
	}
}

以同樣的方式,我們可以寫出消費者的功能函數,然後再在主函數中用CreateThread調用這兩個子程序,生成多線程。

完整代碼:

#include <stdio.h>
#include <windows.h>
#include <time.h>
#define N 10

FILE *fp=NULL;
int flag = -1;
int Buffer[N];
int front=0,rear=0,i=0,j=0;
CRITICAL_SECTION cs;

int random(void){
	int a=time (NULL);
	srand(a);
	return rand()%1000;
}

//子線程函數  
DWORD WINAPI Producer(LPVOID lpParam){
	int number;
	int id = ++i;
	HANDLE full =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"full");
	HANDLE empty =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"empty");
	while(1){
		if(id == 1)	number = random()+1000;
		else number = random()+2000;
		//p(empty)
		WaitForSingleObject(empty,INFINITE); 
		EnterCriticalSection(&cs);
		Buffer[rear]=number;
		printf("生產者%d生產Buffer[%d],%d\n",id,rear,Buffer[rear]);
		flag++;
		if(!flag){
			fp=fopen("C:\\Users\\HP\\Desktop\\記錄.txt","w");
			if(fp==NULL){
				printf("can not load file!");
				exit(0); 
			}
		}
		fprintf(fp,"生產者%d生產Buffer[%d],%d\n",id,rear,Buffer[rear]);
	    rear = (rear+1)%N;
		LeaveCriticalSection(&cs);
		//v(full)
		ReleaseSemaphore(full,1,NULL);
		Sleep(600);
	}
}

//子線程函數  
DWORD WINAPI Consumer(LPVOID lpParam){
	int id = ++j;
	HANDLE full =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"full");
	HANDLE empty =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"empty");
	while(1){
		//p(full)
		WaitForSingleObject(full,INFINITE); 
		EnterCriticalSection(&cs);
    	printf("\t消費者%d消費Buffer[%d],%d\n",id,front,Buffer[front]);
    	flag++;
		if(!flag){
			fp=fopen("C:\\Users\\HP\\Desktop\\記錄.txt","w");
			if(fp==NULL){
				printf("can not load file!");
				exit(0); 
			}
		}
		fprintf(fp,"\t消費者%d消費Buffer[%d],%d\n",id,front,Buffer[front]);
    	front = (front+1)%N;
		LeaveCriticalSection(&cs);
		//v(empty)
		ReleaseSemaphore(empty,1,NULL);
		Sleep(1000);
	}
}  
//主函數  
int main(){
	InitializeCriticalSection(&cs);		//初始化臨界區對象 
	HANDLE full =NULL;
	full = CreateSemaphore(NULL ,0 ,N,"full");
	HANDLE empty =NULL;
	empty = CreateSemaphore(NULL ,N,N,"empty");
    HANDLE hThread[5];
    hThread[0] = CreateThread(NULL,0,Producer,NULL,0,NULL);
    hThread[1] = CreateThread(NULL,0,Producer,NULL,0,NULL);
    hThread[2] = CreateThread(NULL,0,Consumer,NULL,0,NULL);
    hThread[3] = CreateThread(NULL,0,Consumer,NULL,0,NULL);
    hThread[4] = CreateThread(NULL,0,Consumer,NULL,0,NULL);
	WaitForMultipleObjects(5,hThread,TRUE,10000); 	//等待子線程運行 
	fclose(fp);
	CloseHandle(full); 
	CloseHandle(empty); 
    return 0;  
}  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章