www.pudn.com > ThreadCompete.rar > ThreadCollection.cpp


#include "stdafx.h" 
#include "math.h" 
#include "ThreadCompete.h" 
#include "ThreadCollection.h" 
 
int  GetRandomInt( bool bInit, int limit ) 
{	 int result; if(limit<1)return 0; 
     if(bInit)srand( (unsigned)time( NULL ) ); 
	 result = ( rand() ) % limit; 
	 return result; 
} 
 
DWORD  GetPriorityValue( int nCurSel ) 
{	DWORD dw = THREAD_PRIORITY_NORMAL; 
	switch (nCurSel) 
	{ 
	case 1:	dw = (DWORD) THREAD_PRIORITY_IDLE;	break; 
	case 2:	dw = (DWORD) THREAD_PRIORITY_LOWEST;	break; 
	case 3:	dw = (DWORD) THREAD_PRIORITY_BELOW_NORMAL;	break; 
	case 4: 
	default:dw = (DWORD) THREAD_PRIORITY_NORMAL;	break; 
	case 5:	dw = (DWORD) THREAD_PRIORITY_ABOVE_NORMAL;	break; 
	case 6:	dw = (DWORD) THREAD_PRIORITY_HIGHEST;	break; 
	case 7:	dw = (DWORD) THREAD_PRIORITY_TIME_CRITICAL;	break; 
	} 
	return dw; 
} 
 
//统计仍在继续活动执行的线程数, 
//如果采用自动结束方式,而无需变量:m_hEventKill和m_hEventDead 
//此函数也可判别所有线程是否全死 
int CThreadCollection::FinishPersonThreads() 
{	PERSON_INFO * person; DWORD   dwStatus; int i;	int nCount = 0;	 
 
	for(i=personArr.GetUpperBound();i>=0; i--){ 
		person = personArr[i]; 
		if( person && person->pthread ){ 
			//如果现成正常结束执行体或被杀,退出码由dwStatus返回 
			VERIFY(::GetExitCodeThread(person->pthread->m_hThread, &dwStatus)); 
			if (dwStatus == STILL_ACTIVE)		//仍在活动 STATUS_PENDING 
			{	     nCount++; person->pthread->m_bDone = TRUE; 
			}else{	delete person->pthread; //或者person->pthread->KillThread(); 
					person->pthread = NULL; 	} 
		     
		} 
		Sleep(100); 
	} 
	return nCount;  //仍在活动的线程数 
} 
 
void CThreadCollection::FastKillPersonThreads() 
{   PERSON_INFO * person;  int i; 
 
	// 批量执行杀除:tell all threads to shutdown 
	for(i=personArr.GetUpperBound();i>=0; i--){ 
		person = personArr[i]; 
		if( person && person->pthread ){  
			VERIFY( SetEvent(person->pthread->m_hEventKill) ); 
			person->pthread->m_bDone=1; }     
	} 
 
	// wait for all threads to finish shutdown 
	for (int nThreadsLeft = personArr.GetSize(); nThreadsLeft != 0; ) 
	{ 
		//等待任何一个线程结束死亡(退出执行体EndThread) 
		WaitForSingleObject(PersonThread::m_hAnotherDead, INFINITE); 
		Sleep(nThreadsLeft*2);  //线程越多等待越长一点 200ms for every 100 threads 
 
		nThreadsLeft = 0; 
		for(i=personArr.GetUpperBound();i>=0; i--){ 
			person = personArr[i]; 
			if( person && person->pthread ){ //逐个等待线程死亡消息,如超时,则计数 
				if (WaitForSingleObject(person->pthread->m_hEventDead, 0) == WAIT_TIMEOUT) 
					++nThreadsLeft; //超时没杀死: STILL_ACTIVE 的数量 
			} 
		} 
		//如果已经没有线程超时,则表示所有线程均已死亡 
	} 
 
	// 等待线程可析构,并析构对象:delete all thread objects 
	for(i=personArr.GetUpperBound();i>=0; i--){ 
		person = personArr[i]; 
		if( person && person->pthread ){ 
			VERIFY(WaitForSingleObject(person->pthread->m_hThread, INFINITE) == WAIT_OBJECT_0); 
			delete person->pthread;  person->pthread=NULL; 
			personArr.RemoveAt(i); 
		} 
	} 
} 
 
// 利用单个线程的杀除,循环清除集合中所有线程,没有考虑并发清除,速度较慢 
// KillThreadsSlow is much easier to understand since the process of 
// killing a thread is encapsulated in KillThread.  If you get more 
// than 50 threads running, however, you'll notice quite a difference 
// between this method and the one above. 
void CThreadCollection::SlowKillPersonThreads() 
{	// Iterate through the threads killing each 
	// KillThread doesn't return until the Thread is dead 
	for(int i=personArr.GetUpperBound();i>=0; i--){ 
		PERSON_INFO *person = personArr[i]; 
		if( person && person->pthread ){ 
			person->pthread->KillThread(); 
			person->pthread=NULL;   personArr.RemoveAt(i); 
		} 
	} 
} 
 
// 请利用定义FAST_KILL_THREADS,比较两者深度差异 
#define  FAST_KILL_THREADS 
 
void CThreadCollection::DestroyThreadCollection() 
{	  if(!bThreadsPause)ToggleCollectionThreadsPause(true); 
 
	  ToggleCollectionThreadsPause(false); // 让所有线程处于执行中(resume) 
	  //如果是自动结束方式可采用FinishPersonThreads 
 
#ifdef FAST_KILL_THREADS 
	  FastKillPersonThreads();  
#else 
	  SlowKillPersonThreads(); 
#endif 
	  personArr.RemoveAll(); dinnerToolArr.RemoveAll();  
	  threadsResumeArr.RemoveAll(); 
	  competeMap.RemoveAll(); 
} 
 
///////////////////////////////////////////////////////////////////////////////// 
#include "ChildView.h" 
 
CThreadCollection::CThreadCollection() 
{   fSyncChecked=false;  fBlockChecked=false; bUnBlockSelf=false;  
    bThreadsPause=true;  bUpdateNotify=false;  
	// Initialize static members of PersonThread 
	InitializeCriticalSection(&PersonThread::m_criLock); 
} 
CThreadCollection::~CThreadCollection() 
{   DestroyThreadCollection();  
	DeleteCriticalSection(&PersonThread::m_criLock); 
} 
 
void CThreadCollection::SetDisplayCoordinate(CPoint *pt, int ra, int de) 
{	 point = *pt; rr =ra; delta =de;    } 
 
void  CThreadCollection::UpdateNotify( PERSON_INFO * person ) 
{	  if(!bUpdateNotify) return; 
 
	  if(m_pWnd!= NULL){ 
		  CDC*pDC = ((CChildView*)m_pWnd)->GetWindowDC();	//如果不用CChildView类型则坐标无剪   
		  DrawCollectionResult(pDC);  } 
	   
	  if (m_pListBox != NULL) 
	  {	int x = m_pListBox->AddString(person->message);	 
	    m_pListBox->SetCurSel(x); 
		if (m_pListBox->GetCount() > 400)	m_pListBox->DeleteString(0); //保留最近的100条记录 
	  } 
} 
 
void CThreadCollection::DrawCollectionResult(CDC *pDC) 
{ 
	    PERSON_INFO * person;  
	    int x,y,r,xx,yy,dd, size; char chrs[3]; double abc; 
		size = min(personArr.GetSize(),dinnerToolArr.GetSize()); 
		x=point.x;  y=point.y ;	r=rr;  dd = delta;  
 
		//清除显示区 
		//m_dc.Draw3dRect(x,y,cx,cy,RGB(250,250,250),RGB(200,200,200)); 
		pDC->Ellipse(x-r,y-r,x+r,y+r);  //显示餐桌 
        for(int i=0; iDrawText(str, &rc1,0);  
 
				//显示手中的餐具 
				xx = (int)(x+(r+dd)*cos(abc));  
				yy = (int)(y+(r+dd)*sin(abc)); 
                CRect rc(xx-10,yy-10, xx+10,yy+10); 
				if(person->status==FINISHDOWN) 
					strcpy(chrs,"完"); 
				else{ 
					chrs[0] = (person->tools&1) ? 'k':'_'; 
					chrs[1] = (person->tools&2) ? 'f':'_'; 
				} 
				if(person->status==BLOCK)		 pDC->SetTextColor(RGB(255,0,0)); 
				else if(person->status==CATCHING)pDC->SetTextColor(RGB(0,0,255)); 
					else pDC->SetTextColor(RGB(0,0,0)); 
 
				pDC->DrawText(chrs, &rc,0); //dc.SetPixel(xx,yy, RGB(255,0,0)); 
 
 
				//显示桌上所剩餐具	    
				abc = i*PI2/size + PI/size; 
                xx  = (int)(x+(r-2*dd)*cos(abc));  
				yy  = (int)(y+(r-2*dd)*sin(abc)); 
                CRect rc0(xx-10,yy-10, xx+10,yy+10); 
				chrs[0] = (dinnerToolArr[i]&1) ? 'k':'_'; 
				chrs[1] = (dinnerToolArr[i]&2) ? 'f':'_'; 
				pDC->SetTextColor(RGB(0,0,0)); 
			    pDC->DrawText(chrs, &rc0,0);  
		} 
} 
 
////////////////////////////////////////////////////////////////////////////// 
 
int   CThreadCollection::GetItemsUpper() 
{	  return min(personArr.GetUpperBound(),dinnerToolArr.GetUpperBound()); } 
 
void  CThreadCollection::CreateRandomMap(CUIntArray &Arr, int nums) 
{	int i, size, val; 
	Arr.RemoveAll(); 
	while(1){ 
		val = rand()%nums;  //GetRandomInt( nums ); 
		size = Arr.GetSize(); if(size==nums)break;   
		for(i=0; isteptime = delay; 
	} 
} 
 
void  CThreadCollection::initThreadCollectionClass(CWnd* pWnd, CListBox*pBox, int nums, int delay) 
{	  PERSON_INFO * person; 
  
      srand( (unsigned)time( NULL ) ); //初始化随机种子 
	  m_pWnd = pWnd;  m_pListBox=pBox; m_step=0; nContinousPrompt=-1; counter=0;  
	  CreateRandomMap( threadsResumeArr, nums ); 
	  for(int i=0; itools   = 0;			//无刀无叉 
		person->step    = 0;			//第一步 
		person->index   = i;			//位置序号 
		person->status  = CATCHING;		//可取餐具 
		person->pthread = NULL; 
		person->steptime = delay; 
	    person->defaultpriority = GetPriorityValue( 1+GetRandomInt(0,7) ) ; //缺省随机优先级 
		personArr.Add( (PERSON_INFO*)person ); 
		person->compete.what=0;  
	  } 
	  if(person){ 
		  bool bCopy = bUpdateNotify;   bUpdateNotify = true; //显示第一行开始信息	 
		  person->message.Format("There are %d persons to beginging...", nums); 
		  UpdateNotify( person );  bUpdateNotify = bCopy; 
	  } 
	  ((CChildView*)m_pWnd)->Invalidate(); 
} 
 
void CThreadCollection::initCollectionThreads(int nCurSel) 
{	PERSON_INFO * person;  int upper=personArr.GetUpperBound(); 
 
	for(int i=0; i<=upper; i++){ person = personArr[i]; 
		if( person && person->pthread==NULL ){ 
			DWORD dw = (nCurSel==0) ? person->defaultpriority : GetPriorityValue( nCurSel ); 
			person->pthread = CreateBeginThread(person, dw);  } 
	} 
	if(!bThreadsPause)ToggleCollectionThreadsPause(false); //没有挂起则激活所有线程 
} 
 
PersonThread* CThreadCollection::CreateBeginThread( PERSON_INFO * person, DWORD nPriority ) 
{	PersonThread *pThread = new PersonThread(); 
	ASSERT_VALID(pThread); 	if (pThread == NULL)return NULL; 
 
	pThread->m_pThreadParams = NULL;   
	pThread->initPersonThread(this, person);  
	// Create Thread in a suspended state so we can set the Priority before it starts getting away from us 
	if (!pThread->CreateThread(CREATE_SUSPENDED)){	delete pThread;	return NULL;	} 
 
	VERIFY( pThread->SetThreadPriority(nPriority) ); 
	return  pThread; 
 
	//或者可以如下创建 
	//pThread = AfxBeginThread(RUNTIME_CLASS(PersonThread), THREAD_PRIORITY_NORMAL,0, CREATE_SUSPENDED); 
	//if(pThread)pthread->initPersonThread(this, person);  pThread->m_pThreadParams = NULL; return pThread; 
} 
 
// 注意随机顺序与自然顺序的不同效果 
#define RANDOM_RESUME_THREADS 
 
void CThreadCollection::ToggleCollectionThreadsPause(bool bPaused) 
{	PERSON_INFO * person; int i,r,upper; 
	bThreadsPause = bPaused; 
 
#ifdef  RANDOM_RESUME_THREADS 
	upper = threadsResumeArr.GetUpperBound(); 
	for(r=0; r<=upper; r++){ 
		i = threadsResumeArr[r]; if(i>upper)continue;   
		person = personArr[i]; 
		if( person && person->pthread ) { 
			if (bPaused)person->pthread->SuspendThread(); 
			else person->pthread->ResumeThread(); 
		} 
	} 
 
#else 
 
	upper = personArr.GetUpperBound(); 
	for(i=0; i<=upper; i++){ 
		person = personArr[i]; 
		if( person && person->pthread ) { 
			if (bPaused)person->pthread->SuspendThread(); 
			else person->pthread->ResumeThread(); 
		} 
	} 
#endif 
} 
 
DWORD CThreadCollection::SetPersonThreadsPriority( int nCurSel ) 
{	PERSON_INFO * person;  	DWORD dw; 
 
	for(int i=0; i<=personArr.GetUpperBound();i++){ 
		person = personArr[i]; 
		dw     = (nCurSel==0) ? person->defaultpriority : GetPriorityValue( nCurSel ); 
		if( person && person->pthread ) person->pthread->SetThreadPriority(dw); 
	} 
	return dw; 
} 
 
void CThreadCollection::SetCurrentPriorityClass(int nCurSel) 
{	DWORD dw = NORMAL_PRIORITY_CLASS; 
	switch (nCurSel) 
	{ 
	case 0:	dw = IDLE_PRIORITY_CLASS;	break; 
	case 1: 
	default:dw = NORMAL_PRIORITY_CLASS;	break; 
	case 2:	dw = HIGH_PRIORITY_CLASS;	break; 
	case 3:	dw = REALTIME_PRIORITY_CLASS;break; 
	} 
	SetPriorityClass(GetCurrentProcess(), dw); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
 
int   CThreadCollection::CheckPersonCatchStatus(int status) 
{	PERSON_INFO * person; 
 
	for(int i=0; i<=personArr.GetUpperBound(); i++){ 
		person = personArr[i]; 
		if( person && person->pthread ){ 
			if(person->status==status)return 1; 
		} 
	} 
	return 0; //已经没有正在抓取 
} 
 
int   CThreadCollection::CheckPersonFinishStatus() 
{	PERSON_INFO * person; 
 
	for(int i=0; i<=personArr.GetUpperBound(); i++){ 
		person = personArr[i]; 
		if( person && person->pthread ){ 
			if(person->status!=FINISHDOWN)return 0;	} 
	} 
	return 1; //已经全部完成 
} 
 
void  CThreadCollection::PutdownDinnerToolkit(PERSON_INFO * person, int set, int mask) 
{     int index = person->index; 
	  int loc   = (set==KNIFE_BIT) ? person->knife : person->fork; 
	  dinnerToolArr[loc]      |= set;   //放回原地, 一个比特 
	  personArr[index]->tools &= mask;   //清除拿到标志, 也可不清, 因线程已结束 
	 
      person->message.Format("Person %d put back a %s to the location %d", index,  
		   (set==FORK_BIT)?"fork":"knife", loc); 
	  UpdateNotify( person ); 
}		 
 
//在临界区内 
int   CThreadCollection::CatchDinnerToolkit(PERSON_INFO * person, bool fromLeft, bool isFork) 
{	  counter++; bool NeighborsBlocked, SelfBlocked ;   
	  int upper = GetItemsUpper();     int idx = person->index; 	 
	  int loc   = (fromLeft) ? idx: ( (idx==0)?  upper: idx-1 ) ; 
	  int set  = (isFork) ? FORK_BIT  : KNIFE_BIT ;  
	  int mask = (isFork) ? FORK_MASK : KNIFE_MASK; 
 
	  if( !(person->tools & set) && (dinnerToolArr[loc] & set) ){ 
		  dinnerToolArr[loc]	&= mask;		//取走刀或叉, 一个比特 
 
		  //当自己如果不取它,则永久没有机会能拿全时,是否自己优先还是邻居优先? 
		  SelfBlocked      = (person->pthread->CheckOneToolkit(idx, set, upper)==BLOCK) ? true : false ; 
		  NeighborsBlocked = WillBlockNeighbor(idx, set, upper);	 
		  if(SelfBlocked && NeighborsBlocked){ person->compete.loc=loc;person->compete.what=set; } 
 
		  if( !(bUnBlockSelf&&SelfBlocked) && NeighborsBlocked && fBlockChecked){ 
			  dinnerToolArr[loc] |= set;			//不取, 邻居优先 
		  }else{ 
			  person->tools			|= set;			//拿得刀或叉的标志 
			  if(set==FORK_BIT) person->fork= loc;	//拿得叉的位置 
			  else  person->knife	 = loc;			//拿得刀的位置 
			   
			  person->message.Format("Person %d catchs a %s from the %s location %d at step %d", person->index,  
				 (set==FORK_BIT)?"fork":"knife", (fromLeft)?"left":"right",  loc, person->step+1); 
			  UpdateNotify( person );   
			  return 1; 
		  } 
	  } 
	  return 0; 
}		  
 
int   CThreadCollection::WillBlockNeighbor(int iCurrent, int kf, int upper) 
{	  int neighbor, neighborstatus; 
	  for(int left=1; left>=0; left--){  //左右两人	 
		   if(left==1)neighbor = (iCurrent==upper) ? 0: (iCurrent+1); 
		     else     neighbor = (iCurrent==0) ? upper: (iCurrent-1); 
 
		   if(personArr[neighbor] && personArr[neighbor]->pthread){ 
		      neighborstatus = personArr[neighbor]->pthread->CheckOneToolkit(neighbor, kf, upper); 
		      if( neighborstatus==BLOCK ) return 1;   
		   } 
	  } 
	  return 0; 
} 
 
void   CThreadCollection::PromptContinousCheckBox(int show) //SW_SHOW 
{     nContinousPrompt = show ;  
	  if(show==SW_SHOW)m_pWnd->GetDlgItem(IDC_CONTINOUSBTN)->ShowWindow(SW_SHOW);   
} 
 
void   CThreadCollection::StatCompetePersons() 
{       PERSON_INFO * person; 
		for(int i=0; i<=personArr.GetUpperBound(); i++){ 
			person = personArr[i]; 
			if( person && person->compete.what!=0){ 
				person->message.Format("The person %d compete the %s at location %d %s", person->index, 
					(person->compete.what==FORK_BIT)?"fork":"knife", person->compete.loc, (person->status==BLOCK)?": BLOCKED":"GET"); 
				UpdateNotify( person ); person->compete.what=0; 
			}else if(person->status==BLOCK){ 
				person->message.Format("The person %d can not catch the %s anywhere",  
					person->index, (person->tools&FORK_BIT)?"fork":"knife"); 
				UpdateNotify( person ); 
			} 
		} 
		if(!person)person=person = personArr[0]; 
		person->message.Format("下面开始第 %d 轮就餐,第 %d 轮竞争", m_step+1, m_step+2); 
		UpdateNotify( person ); 
}