WIN32 多線程喫字母練習

題目大意

在這裏插入圖片描述
有1個資源區,2個緩衝區(大小爲1),4個喫貨,總共有5個線程,其中一個線程從資源區取字母放到緩衝區,哪個緩衝區是空的就往哪放;4個喫貨線程,從緩衝區喫字母。

該題目要求實現對緩衝區的互斥訪問,緩衝區和資源區必須滿足“緩衝區爲空,才能從資源區取字母”的同步要求,緩衝區和喫貨線程要滿足“緩衝區不空,喫貨才能從緩衝區取字母”的同步要求;除此之外,還要求使用信號量控制喫貨線程最大併發數爲2.

運行結果

在這裏插入圖片描述

代碼

// EatChar.cpp : Defines the entry point for the application.
//

#include "stdafx.h"

HANDLE evtBuffer1Empty, evtBuffer2Empty, evtBuffer1Full, evtBuffer2Full;
HANDLE hSemaphore;
char szBufferRes[100];
char szBuffer1[2], szBuffer2[2];
char szBufferEat[4][100];
HWND hEditEat[4];
HWND hEditRes, hEditBuffer1, hEditBuffer2;
// 負責從資源區取字符,放到緩衝區
// 使用事件實現對緩衝區的互斥訪問
// 不使用MUTEX或CRITICAL_SECTION是因爲事件能實現同步
// 同步的意思是要確保緩衝區爲空才往裏面存字符
DWORD WINAPI ThreadCharToBuffer(LPVOID)
{
	// 只要資源區還有東西,就一直取
	while (szBufferRes[0] != 0)
	{
		Sleep(500);
		// 先看看緩衝區1是否爲空,不等待立即返回
		DWORD dwRet = WaitForSingleObject(evtBuffer1Empty, 0);
		// 如果1空,那麼往1放一個字符
		if (dwRet == WAIT_OBJECT_0)
		{
			szBuffer1[0] = szBufferRes[0];
			//strcpy(szBufferRes, szBufferRes+1);
			memcpy(szBufferRes, szBufferRes+1, strlen(szBufferRes));
			SetWindowText(hEditRes, szBufferRes);
			SetWindowText(hEditBuffer1, szBuffer1);
			SetEvent(evtBuffer1Full);
			continue;
		}
		else
		{
			// 1還有東西,嘗試往2裏放
			dwRet = WaitForSingleObject(evtBuffer2Empty, 0);
			if (dwRet == WAIT_OBJECT_0)
			{
				szBuffer2[0] = szBufferRes[0];
				//strcpy(szBufferRes, szBufferRes+1);
				memcpy(szBufferRes, szBufferRes+1, strlen(szBufferRes));
				SetWindowText(hEditRes, szBufferRes);
				SetWindowText(hEditBuffer2, szBuffer2);	
				SetEvent(evtBuffer2Full);
			}
		}		
	}
	return 0;
}

// 4個線程同時只能有兩個被調度,用信號量實現
DWORD WINAPI ThreadEat(LPVOID p)
{
	// 現在這樣寫應該有兩個線程永遠不執行

	size_t id = (size_t)p;
	// 信號量控制併發數
	
	// 事件控制同步
	while (szBuffer1[0] != 0 || szBuffer2[0] != 0 || szBufferRes[0] != 0)
	{
		Sleep(1000);
		WaitForSingleObject(hSemaphore,INFINITE);
		// 嘗試從1緩衝區取
		DWORD dwRet = WaitForSingleObject(evtBuffer1Full, 0);
		if (dwRet == WAIT_OBJECT_0)
		{
			GetWindowText(hEditEat[id], szBufferEat[id], 100);
			strcat(szBufferEat[id], szBuffer1);
			memset(szBuffer1, 0, 2);
			SetWindowText(hEditBuffer1, szBuffer1);
			SetWindowText(hEditEat[id], szBufferEat[id]);
			SetEvent(evtBuffer1Empty);
		}
		// 嘗試從緩衝區2取
		else
		{
			dwRet = WaitForSingleObject(evtBuffer2Full, 0);
			if (dwRet == WAIT_OBJECT_0)
			{
				GetWindowText(hEditEat[id], szBufferEat[id], 100);
				strcat(szBufferEat[id], szBuffer2);
				memset(szBuffer2, 0, 2);
				SetWindowText(hEditBuffer2, szBuffer2);
				SetWindowText(hEditEat[id], szBufferEat[id]);
				SetEvent(evtBuffer2Empty);				
			}
		}
		ReleaseSemaphore(hSemaphore, 1, NULL);		
	}
	
	return 0;
}

DWORD WINAPI ThreadStart(LPVOID p)
{
	// 必要的初始化工作
	memset(szBufferRes, 0, 100);
	memset(szBuffer1, 0, 2);
	memset(szBuffer2, 0, 2);
	GetWindowText(hEditRes, szBufferRes, 100);
	
	// 初始化事件:緩衝區爲空
	// 事件句柄應當在資源區爲空時關閉
	evtBuffer1Empty = CreateEvent(0, FALSE, TRUE, NULL);
	evtBuffer2Empty = CreateEvent(0, FALSE, TRUE, NULL);
	evtBuffer1Full = CreateEvent(0, FALSE, FALSE, NULL);
	evtBuffer2Full = CreateEvent(0, FALSE, FALSE, NULL);
	// 創建1個資源線程
	HANDLE hThreadCharToBuffer = CreateThread(0,0,ThreadCharToBuffer,0,0,0);
	// 創建信號量控制併發數和4個喫貨線程
	hSemaphore = CreateSemaphore(0,0,4,0); // 最大資源數4
	HANDLE hThreadEat[4];
 	hThreadEat[0] = CreateThread(0,0,ThreadEat,(LPVOID)0,0,0);
 	hThreadEat[1] = CreateThread(0,0,ThreadEat,(LPVOID)1,0,0);
 	hThreadEat[2] = CreateThread(0,0,ThreadEat,(LPVOID)2,0,0);
 	hThreadEat[3] = CreateThread(0,0,ThreadEat,(LPVOID)3,0,0);
	// 釋放兩個資源,這樣同時只能有2個線程被調度
	ReleaseSemaphore(hSemaphore, 2, 0);
	WaitForSingleObject(hThreadCharToBuffer, INFINITE);	
	WaitForMultipleObjects(4, hThreadEat, true, INFINITE);	
	CloseHandle(evtBuffer1Empty);
	CloseHandle(evtBuffer2Empty);
	MessageBox(0,"所有線程結束,所有事件關閉", "", MB_OK);
	return 0;
}

BOOL CALLBACK MainProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
	case WM_INITDIALOG:
		{
			hEditRes = GetDlgItem(hDlg, IDC_EDIT_RES);
			hEditBuffer1 = GetDlgItem(hDlg, IDC_EDIT_BUFFER1);
			hEditBuffer2 = GetDlgItem(hDlg, IDC_EDIT_BUFFER2);
			hEditEat[0] = GetDlgItem(hDlg, IDC_EDIT_A);
			hEditEat[1] = GetDlgItem(hDlg, IDC_EDIT_B);
			hEditEat[2] = GetDlgItem(hDlg, IDC_EDIT_C);
			hEditEat[3] = GetDlgItem(hDlg, IDC_EDIT_D);
			return TRUE;
		}
	case WM_COMMAND:
		{
			switch(LOWORD(wParam))
			{
			case IDC_BUTTON_START:
				{
					HANDLE hThread = CreateThread(0, 0, ThreadStart, 0, 0, 0);
					CloseHandle(hThread);
					return TRUE;
				}
			}
			return TRUE;
		}
	case WM_CLOSE:
		{
			EndDialog(hDlg, 0);
			return TRUE;
		}
	}
	return FALSE;
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
 	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG_MAIN), 0, MainProc);

	return 0;
}




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