www.pudn.com > ThreadCompete.rar > ThreadPerson.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; 
}