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

📄 threadperson.cpp

📁 模拟哲学家就餐过程
💻 CPP
字号:

#include "stdafx.h"
#include "ThreadCompete.h"
#include "ThreadCollection.h"

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

IMPLEMENT_DYNCREATE(PersonThread, CWinThread)

BEGIN_MESSAGE_MAP(PersonThread, CWinThread)
	//{{AFX_MSG_MAP(PersonThread)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

//这是线程互斥同步所需的变量(方案之一)
CRITICAL_SECTION PersonThread::m_criLock;

// m_hAnotherDead is used to signal that one or more threads have ended
//  (it is an auto-reset event; and starts out not signaled)
// 这是每个线程在退出执行体而EndThread时,广播死亡消息所需要的变量
HANDLE PersonThread::m_hAnotherDead = CreateEvent(NULL, FALSE, FALSE, NULL);

void PersonThread::initPersonThread(CThreadCollection *threads, PERSON_INFO*pPerson)
{	m_pThreads = threads; person = pPerson;  m_bDone=0; 
	m_bAutoDelete = 0;  //我们设置非自动结束方式, 也可以采用自动方式

	// kill event starts out in the signaled state
	m_hEventKill = CreateEvent(NULL, TRUE, FALSE, NULL);	//建立消息句柄
	m_hEventDead = CreateEvent(NULL, TRUE, FALSE, NULL);	//建立消息句柄
}

void PersonThread::Delete()
{	CWinThread::Delete();					//在线程执行体自动结束退出时内部调用
	// acknowledge receipt of kill notification
	VERIFY(SetEvent(m_hEventDead));		//通知自己已处于死亡状态
	VERIFY(SetEvent(m_hAnotherDead));	//广播有线程处于死亡状态
}

PersonThread::~PersonThread()
{
	CloseHandle(m_hEventKill);		//关闭消息句柄,必须与建立配对
	CloseHandle(m_hEventDead);		//关闭消息句柄
}

// 单个线程的杀除: 建立KILL消息句柄 ==> 退出执行体 --> 内部 EndThread() --> delete() ==> 
//                 建立DEAD消息句柄 ==> 等待...dead... ==> 等待可析构 ==> 释放对象
void PersonThread::KillThread()
{	// Note: this function is called in the context of other threads, not the thread itself.
	// reset the m_hEventKill which signals the thread to shutdown
	VERIFY(SetEvent(m_hEventKill));  m_bDone=1;
	// allow thread to run at higher priority during kill process
	SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);

	WaitForSingleObject(m_hEventDead, INFINITE);
	WaitForSingleObject(m_hThread, INFINITE);
	delete this;  //析构释放, now delete CWinThread object since no longer necessary
}

/////////////////////////////////////////////////////////////////////////////
// 注意:A) 三个执行体只是选择一个执行:次序为“之一”、“之二”、“之三”
//		 B) 完成后内部执行 afxEndThread 退出
/////////////////////////////////////////////////////////////////////////////

#define  INSTANCE_LOOP_MODE

// 1、线程执行体之一
//    如果定义了pThread->m_pfnThreadProc,则执行 (*pThread->m_pfnThreadProc)(pThread->m_pThreadParams);

// 2、线程执行体之二
BOOL PersonThread::InitInstance()
{	 CWinThread::InitInstance();
	 m_bDone = (m_pThreads == NULL)? 1: 0; int ret;

#ifdef  INSTANCE_LOOP_MODE
	 //可以在此安排线程执行体,并使返回FALSE,例如:
	 while (1){
		ret = (WaitForSingleObject(m_hEventKill, 0)!= WAIT_TIMEOUT);
		if(ret || m_bDone) break; //没有时间没有超长,则说明被杀了
		ThreadSingleStepRun();  
	 }
	 return false;  //如果返回 FALSE 执行ExitInstance, 给出返回码
#else
	 return true;   //如果返回 TRUE 则执行 Run()
#endif
}

// 3、线程执行体之三: 
int PersonThread::Run()
{
	if (m_pThreads == NULL)return -1;

#ifndef INSTANCE_LOOP_MODE
	 m_bDone = 0;
	 while (1){
		int ret = (WaitForSingleObject(m_hEventKill, 0)!= WAIT_TIMEOUT);
		if(ret || m_bDone) break; //没有时间没有超长,则说明被杀了
		ThreadSingleStepRun();  
	 }

	return 0; ////返回退出码: 退出后执行 afxEndThread(), 如果m_bAutoDelete=1 则自动结束线程
#endif

    return 0;
}

/////////////////////////////////////////////////////////////////////////////

void PersonThread::ThreadSingleStepRun()
{
	int isSomeOneCatch, isSomeBlock, oldStatus, result=0; bool bFirstOne=false,bStarting=false;
	if (m_pThreads == NULL) return ;

	CSingleLock sLock( (CSyncObject*)&(m_pThreads->m_mutex) );
	if (m_pThreads->fSyncChecked)sLock.Lock(); 
	  //临界区代码
	  person->status = CheckPersonStatus(oldStatus);
	  isSomeOneCatch = m_pThreads->CheckPersonCatchStatus(CATCHING);
	  isSomeBlock    = m_pThreads->CheckPersonCatchStatus(BLOCK);

      if(person->status==BEGINEATING && !isSomeOneCatch ){//一轮竞争结束时
	      bFirstOne = m_pThreads->m_step==person->step;
		  bStarting = (m_pThreads->nContinousPrompt == -1);//复位?
		  if(isSomeBlock && bFirstOne && bStarting){       //如果有人没得餐具又无提示,则第一人时提示
			  m_pThreads->StatCompetePersons();
			  m_pThreads->PromptContinousCheckBox(SW_SHOW);//提示后就在该第一人处等待提示消失 
			  while(m_pThreads->nContinousPrompt==SW_SHOW)Sleep(10);//提示消失时开始就餐,//延时后放下 
			  m_pThreads->m_step++;
			  m_pThreads->PromptContinousCheckBox(-1); //复位准备下一轮
		  }
	  }else bStarting=false;
	if (m_pThreads->fSyncChecked) sLock.Unlock();

	switch(person->status){
		case CATCHING:    {	result = CatchDinnerToolkit();	break; } //临界区代码
		case BEGINEATING: { 
			if(bStarting){ //已无人正在取物....
				DelayStepTime( m_bDone );	m_bDone=true; //延时后放下 
				if (m_pThreads->fSyncChecked)sLock.Lock();
				    //临界区代码
					PutdownDinnerToolkit(); 
				if (m_pThreads->fSyncChecked) sLock.Unlock();
			}
			break; }
		case BLOCK:	break;
	}
	
	// A call to Sleep() here tells the system that we want to relinquis 
	// the remainder of our time slice to another thread. this call is needed   
	// for single-CPU systems so that the results of the synchronization or 
	// lack thereof are obvious. Normally, your programs would NOT call Sleep() here.
	if(person->status != FINISHDOWN) Sleep(3000); //适当大些显示效果好些 (>=0)
}

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

void  PersonThread::DelayStepTime(BOOL bDone)
{
	Sleep( 10*person->steptime);
/*
	time_t now = time(&now);
	while (!bDone){
		time_t ntime = time(&ntime) - now;   //时间差
		if( ntime > (TIME_BASE * person->steptime) )  break; 
		Sleep(10);	}
*/
}

int  PersonThread::CheckOneToolkit(int index, int kf, int upper)
{	 if( !(person->tools & kf) ){
		 for(int left=1; left>=0; left--){	//方位:左或右
		     int lr = (left==1) ? index: ( (index==0)?  upper: index-1 ) ;
			 if( (m_pThreads->dinnerToolArr[lr]&kf) ){
				  return CATCHING; }//手中缺刀叉,但桌上相应位置也有刀叉---可取
		}//for
		return BLOCK;
	 }//if
	 return BEGINEATING;
}

int  PersonThread::CheckPersonStatus(int &oldstatus)
{	 int status, upper, kf=KNIFE_BIT;  oldstatus = person->status; 
	 if(oldstatus==FINISHDOWN)return FINISHDOWN;

	 upper = m_pThreads->GetItemsUpper();
	 if( person->tools!=(KNIFE_BIT|FORK_BIT) ) { //工具:刀或叉
		 if( !(person->tools & KNIFE_BIT) ){
			status = CheckOneToolkit(person->index, KNIFE_BIT, upper);
			if(status==CATCHING) return CATCHING; }//手中缺刀,但桌上相应位置也有刀---可取 

		 if( !(person->tools & FORK_BIT) ){
			status = CheckOneToolkit(person->index, FORK_BIT, upper);
			if(status==CATCHING) return CATCHING; }//手中缺叉,但桌上相应位置也有叉---可取 
	 }else return BEGINEATING;		//手中有刀叉---完成
	 return BLOCK;
}

void PersonThread::PutdownDinnerToolkit( )
{	
	person->status = FINISHDOWN;
	if(person->tools & KNIFE_BIT){    //放回原地
		m_pThreads->PutdownDinnerToolkit(person, KNIFE_BIT, KNIFE_MASK);
	}
	if(person->tools & FORK_BIT){     //放回原地
		m_pThreads->PutdownDinnerToolkit(person, FORK_BIT, FORK_MASK);
	}

	if(m_pThreads && m_pThreads->m_pWnd && m_pThreads->CheckPersonFinishStatus()){
		int upper = m_pThreads->GetItemsUpper(); upper = (upper<0)?0: (upper+1);
		person->message.Format("The %d persons to ending...", upper);
		m_pThreads->UpdateNotify( person );
		m_pThreads->m_pWnd->SendMessage(WM_USER_NOTIFY,upper,0);
	}
}

// ........ 适当修改此函数,可以得到不同的算法效果.............

int PersonThread::CatchDinnerToolkit( )
{	//如果“餐具”和“方向”非完全随机,则算法有倾向性
	//另外如果各线程的优先级不同或每人的 steptime 不同,则算法更有倾向性
	bool isFork, fromLeft;
	if((person->tools & KNIFE_BIT)||(person->tools & FORK_BIT)){ 
		isFork = ((person->tools & FORK_BIT)>0) ? false : true;
	}else{ for(int i=0; i<= person->index; i++) rand(); isFork = rand()&1; } //空手?

	for(int i=0; i<= person->index; i++) rand();  fromLeft =  rand()&1;

    person->step = m_pThreads->m_step;
	if (m_pThreads->fSyncChecked) EnterCriticalSection(&PersonThread::m_criLock);
	  int result = m_pThreads->CatchDinnerToolkit( person, fromLeft, isFork);  //取走刀或叉
	  //一侧没取到则在另一侧取一下, 当然此句可省略
	  if(!result)result = m_pThreads->CatchDinnerToolkit( person, !fromLeft, isFork); 
	if (m_pThreads->fSyncChecked) LeaveCriticalSection(&PersonThread::m_criLock);

	return result;
}

⌨️ 快捷键说明

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