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




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