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 );
}