📄 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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -