IPC典型模型-哲学家纠缠问题

Posted yuanshijie

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IPC典型模型-哲学家纠缠问题相关的知识,希望对你有一定的参考价值。

1965年dijkstra提出了一个关于进程同步问题,大致意思如下:

有5个哲学家坐在一张圆桌上,每个哲学家左右两边各有一个叉子。

只有当集齐两个叉子,才能够吃饭,否则哲学家就得乖乖去思考。

桌子上就5个叉子,理论上同时可以让两个哲学家进餐,那么怎么用两个进程来模拟这个状态呢?

 

0x001

这几个哲学家可以视作一个进程开了5次。我们来创建一个哲学家进程,代码如下:

  用_tagCOMMUNICATIONOBJECT存放公共的数据,放在公共的内存中。

#include "stdafx.h"
#include <Windows.h>
#include<iostream>
#define EATING_TIME			1000
#define PHILOSOPHER_COUNT	5
#define WM_INVALIDATE		WM_USER + 1
//公用的数据,放到映射的内存中的数据
using namespace std;
typedef struct _tagCOMMUNICATIONOBJECT
{
	HWND	hWnd;
	bool	bExitApplication;
	int		iPhilosopherArray[PHILOSOPHER_COUNT];
	int		PhilosopherCount;
} COMMUNICATIONOBJECT, * PCOMMUNICATIONOBJECT;
void Eat();//吃饭饭
TCHAR* szSemaphoreName = TEXT("__PD_SEMAPHORE__");//信号量名称
TCHAR* szMappingName = TEXT("__SHARED_FILE_MAPPING__");//映射内存名称
bool bExitApplication = false;//退出应用标志
int _tmain(int argc, _TCHAR* argv[])
{
	//获取控制台句柄
	HWND Hconsole = GetConsoleWindow();
	ShowWindow(Hconsole, SW_HIDE);//隐藏控制台窗口
	int index = (int)_tcstol(argv[0], NULL, 10);//获取当前进程代号
		//读取映射内容
	HANDLE hMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, szMappingName);
	if (!hMapping)
	{
		cout << "hMapping打开失败!" << endl;
		cout << GetLastError() << endl;
		return -1;
	}//映射内容一旦打开,未关闭时,一直处于可操作状态
	while (!bExitApplication)
	{
		//打开信号量
		HANDLE hSemaphore = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, szSemaphoreName);
		if (!hSemaphore)
		{
			cout << "sempahore创建失败!" << endl;
			cout << GetLastError() << endl;
			return -1;
		}
		
		//等待信号量触发
		WaitForSingleObject(hSemaphore, INFINITE);//等待信号对象

		//从映射对象中读取通用变量
		PCOMMUNICATIONOBJECT pcomobj = (PCOMMUNICATIONOBJECT)MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS,
			0, 0, sizeof(COMMUNICATIONOBJECT));
		if (!pcomobj)
		{
			cout << "pcomobj创建失败!" << endl;
			cout << GetLastError() << endl;
			return -1;
		}
		bExitApplication = pcomobj->bExitApplication;//获取循环标志
		if (!pcomobj->iPhilosopherArray[(index + pcomobj->PhilosopherCount - 1) % pcomobj->PhilosopherCount] &&
			!pcomobj->iPhilosopherArray[(index + pcomobj->PhilosopherCount + 1) % pcomobj->PhilosopherCount])
		{
			pcomobj->iPhilosopherArray[index] = 1;
			Eat();//吃饭
		}
		SendMessage(pcomobj->hWnd, WM_INVALIDATE, 0, 0);//向另一个窗口发送消息
		pcomobj->iPhilosopherArray[index] = 0;//吃完饭置为0
		ReleaseSemaphore(hSemaphore, 1, NULL);//针对一个信号量
		UnmapViewOfFile(pcomobj);//关闭文件映射
		CloseHandle(hSemaphore);//关闭信号量句柄
	}

	CloseHandle(hMapping);//关闭文件映射句柄
	return 0;//返回
}
void Eat()
{
	Sleep(EATING_TIME);//停顿一段时间用于吃饭
}

0x02 

创建一个进程来控制哲学家进餐

#include "stdafx.h"
#include<iostream>
using namespace std;
#define BUTTON_CLOSE			100
#define PHILOSOPHER_COUNT		5
#define WM_INVALIDATE			WM_USER + 1
typedef struct _tagCOMMUNICATIONOBJECT
{
	HWND	hWnd;
	bool	bExitApplication;
	int		iPhilosopherArray[PHILOSOPHER_COUNT];
	int		PhilosopherCount;
} COMMUNICATIONOBJECT, *PCOMMUNICATIONOBJECT;
HWND InitInstance(HINSTANCE hInstance, int nCmdShow);
ATOM MyRegisterClass(HINSTANCE hInstance);
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int PhilosopherPass(int iPhilosopher);
void FillEllipse(HWND hWnd, HDC hDC, int iLeft, int iTop, int iRight, int iBottom, int iPass);
TCHAR* szTitle = TEXT("Philosophers Dinner Demo");
TCHAR* szWindowClass = TEXT("__PD_WND_CLASS__");
TCHAR* szSemaphoreName = TEXT("__PD_SEMAPHORE__");
TCHAR* szMappingName = TEXT("__SHARED_FILE_MAPPING__");
PCOMMUNICATIONOBJECT pCommObject = NULL;
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	//未使用的变量不出现警告
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);
	HANDLE hMapping = CreateFileMapping((HANDLE)-1, NULL,
		PAGE_READWRITE, 0, sizeof(COMMUNICATIONOBJECT), szMappingName);
	if (!hMapping)
	{
		cout << "hMapping为空!" << endl;
		cout << GetLastError() << endl;
		return -1;
	}
	pCommObject = (PCOMMUNICATIONOBJECT)MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
	if (!pCommObject)
	{
		cout << "pcommobject为空!" << endl;
		cout << GetLastError() << endl;
		return -1;
	}
	HANDLE hSemaphore = CreateSemaphore(NULL, (PHILOSOPHER_COUNT / 2),
		(PHILOSOPHER_COUNT / 2),szSemaphoreName);
	if (!hSemaphore)
	{
		cout << "hsemaphore为空!" << endl;
		cout << GetLastError() << endl;
		return -1;
	}
	InitCommonControls();//初始化通用控件
	MyRegisterClass(hInstance);//注册
	HWND hwnd = InitInstance(hInstance,nCmdShow);//初始化
	if (!hwnd)
	{
		cout << "hwnd为空!" << endl;
		cout << GetLastError() << endl;
		return -1;
	}
	pCommObject->hWnd = hwnd;
	pCommObject->bExitApplication = false;
	pCommObject->PhilosopherCount = PHILOSOPHER_COUNT;
	memset(pCommObject->iPhilosopherArray, 0,sizeof(*pCommObject->iPhilosopherArray));
	//开启进程
	STARTUPINFO starupinfo[PHILOSOPHER_COUNT] = { {0},{0},{0},{0},{0} };
	PROCESS_INFORMATION processInfo[PHILOSOPHER_COUNT]= { {0},{0},{0},{0},{0} };
	HANDLE hProcess[PHILOSOPHER_COUNT] = { 0 };
	TCHAR szBuffer[8] = {0};
	for (int i = 0; i < PHILOSOPHER_COUNT; i++)
	{
		wsprintf(szBuffer, TEXT("%d"), i);
		if (CreateProcess(TEXT("..\Debug\Philosopher.exe"), szBuffer, NULL,
			NULL,
			FALSE,
			NULL,
			NULL,
			NULL,
			&starupinfo[i],
			&processInfo[i]))
		{
			hProcess[i] = processInfo[i].hProcess;
		}
	}
	MSG msg = { 0 };
	while (GetMessage(&msg, hwnd, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	pCommObject->bExitApplication = true;
	UnmapViewOfFile(pCommObject);//关闭文件映射
	for (int i = 0; i < PHILOSOPHER_COUNT; i++)
	{
		CloseHandle(hProcess[i]);//关闭进程句柄
	}
	CloseHandle(hMapping);
	return (int)msg.wParam;//返回消息参数0
}
//ATOM==word
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wndEx;
	wndEx.cbSize = sizeof(WNDCLASSEX);
	wndEx.style = CS_HREDRAW | CS_VREDRAW;
	wndEx.lpfnWndProc = WndProc;
	wndEx.cbClsExtra = 0;
	wndEx.cbWndExtra = 0;
	wndEx.hInstance = hInstance;
	wndEx.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
	wndEx.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndEx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wndEx.lpszMenuName = NULL;
	wndEx.lpszClassName = szWindowClass;
	wndEx.hIconSm = LoadIcon(wndEx.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
	return RegisterClassEx(&wndEx);
}
//初始化
HWND InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPED | WS_CAPTION
		| WS_SYSMENU | WS_MINIMIZEBOX, 200, 200, 540, 590, NULL, NULL, hInstance, NULL);
	if (!hWnd)
	{
		return NULL;
	}
	HFONT hFont = CreateFont(14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET, OUT_DEFAULT_PRECIS, 
		CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_MODERN, TEXT("Microsoft Sans Serif"));
	HWND hButton = CreateWindow(TEXT("BUTTON"), TEXT("Close"), WS_CHILD | WS_VISIBLE 
		| BS_PUSHBUTTON | WS_TABSTOP, 410, 520, 100, 25, hWnd, (HMENU)BUTTON_CLOSE, hInstance, NULL);
	SendMessage(hButton, WM_SETFONT, (WPARAM)hFont, TRUE);
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);
	return hWnd;
}
//回调函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_COMMAND:
	{
		switch (LOWORD(wParam))
		{
		case BUTTON_CLOSE:
		{
			DestroyWindow(hWnd);
			break;
		}
		}
		break;
	}
	case WM_INVALIDATE:
	{
		//更新指定的窗口区域
		InvalidateRect(hWnd, NULL, TRUE);//接受philosopher发来的消息,进行处理
		break;
	}
	case WM_PAINT:
	{
		PAINTSTRUCT paintStruct;
		HDC hDC = BeginPaint(hWnd, &paintStruct);
		FillEllipse(hWnd, hDC, 210, 10, 310, 110, PhilosopherPass(1));//圆圈1
		FillEllipse(hWnd, hDC, 410, 170, 510, 270, PhilosopherPass(2));//圆圈2
		FillEllipse(hWnd, hDC, 335, 400, 435, 500, PhilosopherPass(3));//圆圈3
		FillEllipse(hWnd, hDC, 80, 400, 180, 500, PhilosopherPass(4));//圆圈4
		FillEllipse(hWnd, hDC, 10, 170, 110, 270, PhilosopherPass(5));//圆圈5
		EndPaint(hWnd, &paintStruct);//结束绘制
		break;
	}
	case WM_DESTROY:
	{
		PostQuitMessage(0);
		break;
	}
	default:
	{
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
	}
	}
	return 0;
}
//哲学家
int PhilosopherPass(int iPhilosopher)
{
	return pCommObject->iPhilosopherArray[iPhilosopher - 1];
}
//填充圆圈
void FillEllipse(HWND hWnd, HDC hDC, int iLeft, int iTop, int iRight, int iBottom, int iPass)
{
	HBRUSH hBrush = NULL;
	if (iPass)//哲学家状态非0,填充红色
	{
		hBrush = CreateSolidBrush(RGB(255, 0, 0));
	}
	else//哲学家状态为0,填充白色
	{
		hBrush = CreateSolidBrush(RGB(255, 255, 255));
	}
	HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);//选中画刷1
	Ellipse(hDC, iLeft, iTop, iRight, iBottom);//绘制圆形
	SelectObject(hDC, hOldBrush);//填充颜色
	DeleteObject(hBrush);//用完之后清空选中的句柄
}

  

 

以上是关于IPC典型模型-哲学家纠缠问题的主要内容,如果未能解决你的问题,请参考以下文章

典型的进程间通信IPC问题-生产者消费者问题

实验精神终将胜利:量子纠缠的祛魅七十年

实验精神终将胜利:量子纠缠的祛魅七十年

IPC之哲学家进餐问题

IPC问题-哲学家就餐

一位高级数据科学家典型的一天:从结对编程敏捷开发,到编写代码