⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 philosopherview.cpp

📁 关于操作系统哲学家进餐的动态演示程序
💻 CPP
字号:
// PhilosopherView.cpp : implementation of the CPhilosopherView class
//

#include "stdafx.h"
#include "Philosopher.h"

#include "PhilosopherDoc.h"
#include "PhilosopherView.h"
#include "math.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


BOOL chopSticks[PHIL_NUM] = {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE};
BOOL Finished[PHIL_NUM] ={TRUE, TRUE, TRUE, TRUE, TRUE, TRUE};
CMutex *m_pMutex = NULL;
CEvent *m_pEvent = NULL;

UINT DineOnce(LPVOID pParam);
UINT DineMany(LPVOID pParam);
/////////////////////////////////////////////////////////////////////////////
// CPhilosopherView

IMPLEMENT_DYNCREATE(CPhilosopherView, CView)

BEGIN_MESSAGE_MAP(CPhilosopherView, CView)
	//{{AFX_MSG_MAP(CPhilosopherView)
	ON_COMMAND(ID_PLAY_ONCE, OnPlayOnce)
	ON_COMMAND(ID_PLAY_MANY, OnPlayMany)
	ON_UPDATE_COMMAND_UI(ID_PLAY_MANY, OnUpdatePlayMany)
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPhilosopherView construction/destruction

CPhilosopherView::CPhilosopherView()
{
	// TODO: add construction code here
	for(int i = 0; i < PHIL_NUM; i++)
		m_pThread[i] = NULL;
	m_pMutex = new CMutex;  //用于控制对数组chopSticks的访问
	m_pEvent = new CEvent(FALSE, TRUE); //用于控制线程,让线程同时开始执行,bManualReset 为true
}

CPhilosopherView::~CPhilosopherView()
{
	delete m_pMutex;
	delete m_pEvent;
}

BOOL CPhilosopherView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CPhilosopherView drawing

void CPhilosopherView::OnDraw(CDC* pDC)
{
	CPhilosopherDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
	int chopStartX[6], chopStartY[6], chopEndX[6], chopEndY[6];
	int philX[6], philY[6];
	int i;
	CPen pen(PS_SOLID, 3, RGB(0, 0, 0));
	CRect rect = CRect(150, 150, 150+DESK_DIAMETER, 150+DESK_DIAMETER);

	//画圆桌
	pDC->Ellipse(rect);
	CHOP_COORDINATE(150, 150);
	CPen *pOldPen = (CPen*)pDC->SelectObject(&pen);

	//画筷子
	for(i = 0; i < PHIL_NUM; i++)
	{
		pDC->MoveTo(chopStartX[i], chopStartY[i]);
		pDC->LineTo(chopEndX[i], chopEndY[i]);
	}
	pDC->SelectObject(pOldPen);
	PHIL_COORDINATE(150, 150);

	//画哲学家
	for(i = 0; i< PHIL_NUM; i++)
	{
		pDC->Ellipse(philX[i], philY[i], philX[i] + PHIL_DIAMETER, philY[i] + PHIL_DIAMETER); 
	}
}

/////////////////////////////////////////////////////////////////////////////
// CPhilosopherView printing

BOOL CPhilosopherView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CPhilosopherView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CPhilosopherView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CPhilosopherView diagnostics

#ifdef _DEBUG
void CPhilosopherView::AssertValid() const
{
	CView::AssertValid();
}

void CPhilosopherView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CPhilosopherDoc* CPhilosopherView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPhilosopherDoc)));
	return (CPhilosopherDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CPhilosopherView message handlers

void CPhilosopherView::OnPlayOnce() 
{
	// TODO: Add your command handler code here
	int i, left, right;
	int chopStartX[6], chopStartY[6], chopEndX[6], chopEndY[6];
	int philX[6], philY[6];
	PARAM *pParam = NULL;
    
	for(i = 0; i < PHIL_NUM; i++)
	{
		chopSticks[i] = FALSE;  //初始时筷子可用
	}
	m_pEvent->ResetEvent(); //初始时,m_pEvent不可访问

	CHOP_COORDINATE(150, 150);  //生成筷子的坐标
	PHIL_COORDINATE(150, 150);  //生成哲学家的坐标
	for(i = 0; i < PHIL_NUM; i++)
	{ //生成要传入线程的参数

		pParam = new PARAM;
		if(NULL == pParam)
		{
			break;
		}
		pParam->Id = i;
		pParam->m_hWnd = this->m_hWnd;
		pParam->philX = philX[i];
		pParam->philY = philY[i];
		left = i;
		right = (i+1) % PHIL_NUM;
		pParam->chopXY[0] = chopStartX[left];
		pParam->chopXY[1] = chopStartY[left];
		pParam->chopXY[2] = chopEndX[left];
		pParam->chopXY[3] = chopEndY[left];
		pParam->chopXY[4] = chopStartX[right];
		pParam->chopXY[5] = chopStartY[right];
		pParam->chopXY[6] = chopEndX[right];
		pParam->chopXY[7] = chopEndY[right];

		m_pThread[i] = AfxBeginThread(DineOnce, (LPVOID)pParam);
	}

	//Invalidate();
	//Invalidate(FALSE);
	m_pEvent->SetEvent();//是m_pEvent可访问,激活所有的哲学家线程
	pParam = NULL;
}

/**********************************************************************
DineOnce 线程函数一直处于Lock的调用,这是因为线程的启动也要一段时间,若线程
执行的时间小于线程创建的时间,则有可能先被创建的线程已经执行完毕,而
后面的线程还没开始执行。
***********************************************************************/
UINT DineOnce(LPVOID pParam)
{
	m_pEvent->Lock(); //线程阻塞,直到全部的线程都被启动,从而使所有的线程同时执行
	PARAM *m_pParam = (PARAM*)pParam;
	int left, right;
	BOOL canDine = FALSE;
	CWnd wnd;
	CDC *pDC;
	CPen pen;
	CBrush brush, *pOldBrush;

	left = m_pParam->Id;
	right = (m_pParam->Id + 1) % PHIL_NUM;

	//检查筷子是否可用,若可用则进餐
	m_pMutex->Lock();
	if(FALSE == chopSticks[left]
	   && FALSE == chopSticks[right])
	{
		chopSticks[left] = chopSticks[right] = TRUE;
		canDine = TRUE;
	}
	m_pMutex->Unlock();
	
	wnd.Attach(m_pParam->m_hWnd);
    pDC=wnd.GetDC();

	//根据是否可就餐画图
	if(TRUE == canDine)
	{
		brush.CreateSolidBrush(RGB(0, 255, 0));
		pOldBrush=(CBrush*)pDC->SelectObject(&brush);
		pDC->Ellipse(m_pParam->philX, m_pParam->philY,
					 m_pParam->philX + PHIL_DIAMETER, m_pParam->philY + PHIL_DIAMETER); 
		pen.CreatePen(PS_SOLID, 3, RGB(0, 255, 0));
		pDC->SelectObject(&pen);
		pDC->MoveTo(m_pParam->philX + PHIL_DIAMETER/2, m_pParam->philY + PHIL_DIAMETER/2);
		pDC->LineTo(m_pParam->chopXY[2], m_pParam->chopXY[3]);
		pDC->MoveTo(m_pParam->philX + PHIL_DIAMETER/2, m_pParam->philY + PHIL_DIAMETER/2);
		pDC->LineTo(m_pParam->chopXY[6], m_pParam->chopXY[7]);
		pDC->SelectObject(pOldBrush);
	}
	else
	{
		brush.CreateSolidBrush(RGB(255, 0, 0));
		pOldBrush=(CBrush*)pDC->SelectObject(&brush);
		pDC->Ellipse(m_pParam->philX, m_pParam->philY,
					 m_pParam->philX + PHIL_DIAMETER, m_pParam->philY + PHIL_DIAMETER); 
		pDC->SelectObject(pOldBrush);
	}
	wnd.Detach();
	delete m_pParam;
	return 0L;
}


void CPhilosopherView::OnPlayMany() 
{
	// TODO: Add your command handler code here
	int i, left, right;
	int chopStartX[6], chopStartY[6], chopEndX[6], chopEndY[6];
	int philX[6], philY[6];
	PARAM *pParam = NULL;
    
	for(i = 0; i < PHIL_NUM; i++)
	{
		chopSticks[i] = FALSE;
	}

	//Finished数字的作用用来表示线程是否已经执行完成,用于控制“进行多次”菜单是否可以使用
	for (i =0; i< PHIL_NUM; i++)
	{
		Finished[i] = FALSE; //初始时,Finished为false,若线程执行完成,Finished为true
	}
	m_pEvent->ResetEvent();

	CHOP_COORDINATE(150, 150);
	PHIL_COORDINATE(150, 150);
	for(i = 0; i < PHIL_NUM; i++)
	{
		pParam = new PARAM;
		if(NULL == pParam)
		{
			break;
		}
		pParam->Id = i;
		pParam->m_hWnd = this->m_hWnd;
		pParam->philX = philX[i];
		pParam->philY = philY[i];
		left = i;
		right = (i+1) % PHIL_NUM;
		pParam->chopXY[0] = chopStartX[left];
		pParam->chopXY[1] = chopStartY[left];
		pParam->chopXY[2] = chopEndX[left];
		pParam->chopXY[3] = chopEndY[left];
		pParam->chopXY[4] = chopStartX[right];
		pParam->chopXY[5] = chopStartY[right];
		pParam->chopXY[6] = chopEndX[right];
		pParam->chopXY[7] = chopEndY[right];

		m_pThread[i] = AfxBeginThread(DineMany, (LPVOID)pParam);
	}

	Invalidate();
	m_pEvent->SetEvent(); //同上的解释
	pParam = NULL;
}

/////////////////////////////////////////////////////////////////////////////
UINT DineMany(LPVOID pParam)
{
	m_pEvent->Lock();
	PARAM *m_pParam = (PARAM*)pParam;
	int left, right;
	int TimeDelay = TIME, SleepTime;
	BOOL canDine = FALSE;
	CWnd wnd;
	CDC *pDC;
	CPen pen1, pen2, *pOldPen;
	CBrush brush1, brush2, *pOldBrush;

	left = m_pParam->Id;
	right = (m_pParam->Id + 1) % PHIL_NUM;
	
	wnd.Attach(m_pParam->m_hWnd);
    pDC=wnd.GetDC();
	brush1.CreateSolidBrush(RGB(0, 255, 0));
	brush2.CreateSolidBrush(RGB(255, 0, 0));
	pen1.CreatePen(PS_SOLID, 3, RGB(0, 255, 0));
	pen2.CreatePen(PS_SOLID, 3, RGB(255, 255, 255));
	while(TimeDelay > 0)
	{
		m_pMutex->Lock();
		if(FALSE == chopSticks[left]
			&& FALSE == chopSticks[right])
		{
			chopSticks[left] = chopSticks[right] = TRUE;
			canDine = TRUE;
		}
		m_pMutex->Unlock();
		if(TRUE == canDine)
		{
			
			pOldBrush = (CBrush*)pDC->SelectObject(&brush1);
			pDC->Ellipse(m_pParam->philX, m_pParam->philY,
						m_pParam->philX+PHIL_DIAMETER, m_pParam->philY+PHIL_DIAMETER); 
			
			pDC->SelectObject(&pen1);
			pDC->MoveTo(m_pParam->philX+PHIL_DIAMETER/2, m_pParam->philY + PHIL_DIAMETER/2);
			pDC->LineTo(m_pParam->chopXY[2], m_pParam->chopXY[3]);
			pDC->MoveTo(m_pParam->philX + PHIL_DIAMETER/2, m_pParam->philY + PHIL_DIAMETER/2);
			pDC->LineTo(m_pParam->chopXY[6], m_pParam->chopXY[7]);
			srand((unsigned)time(NULL));
			SleepTime = ((rand() % 250 +250) - (rand() % 250 -250)) / 2;
			Sleep(SleepTime);
			TimeDelay -= SleepTime;
			if(TimeDelay < 0 ) break;

			//进餐后,防线筷子给其他哲学家使用
			m_pMutex->Lock();
			chopSticks[left] = chopSticks[right] = FALSE;
			m_pMutex->Unlock();

			//开始思考
			canDine = FALSE;
		}
		if(FALSE == canDine)
		{
			
			pOldPen = (CPen*)pDC->SelectObject(&pen2);
			pDC->MoveTo(m_pParam->philX + PHIL_DIAMETER/2, m_pParam->philY + PHIL_DIAMETER/2);
			pDC->LineTo(m_pParam->chopXY[2], m_pParam->chopXY[3]);
			pDC->MoveTo(m_pParam->philX + PHIL_DIAMETER/2, m_pParam->philY + PHIL_DIAMETER/2);
			pDC->LineTo(m_pParam->chopXY[6], m_pParam->chopXY[7]);
			pDC->SelectObject(&brush2);
			pDC->Ellipse(m_pParam->philX, m_pParam->philY,
						m_pParam->philX + PHIL_DIAMETER, m_pParam->philY + PHIL_DIAMETER);		
			pDC->SelectObject(pOldPen);

			//思考一段时间
			srand((unsigned)time(NULL));
			SleepTime = ((rand() % 500 +500) - (rand() % 500 -500)) / 2;
			Sleep(SleepTime);

			//将持续时间减去思考时间
			TimeDelay -= SleepTime;
		}
	}
	wnd.Detach();
	Finished[m_pParam->Id] = TRUE;  //线程执行完成
	delete m_pParam;
	return 0L;
}

void CPhilosopherView::OnUpdatePlayMany(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	int i;
	BOOL flag = TRUE;
	for (i =0; i < PHIL_NUM; i++)
	{
		//若还有线程没有执行完成,则菜单不可用
		if (FALSE == Finished[i])
		{
			flag = FALSE;
			break;
		}
	}
	pCmdUI->Enable(flag);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -