多线程经典问题----考试问题

1.问题描述:

1个主考官,n个学生

考官和学生陆续进入教室(没有先后之分)。等待所有学生进入教室后,考官开始发考卷

考官把考卷发给所有学生后,学生才开始答题,学生可以提前交卷,交完卷后即可离开教室。

老师等所有学生交完卷后才能离开教室。

2.问题解答:

本题和乘客乘公交车问题类似,主要考察多线程的同步和互斥。

主类和主线程如下:

#include "afxmt.h"

#define STUDENTCOUNT 10

class CExamQuestion
{
public:
	CExamQuestion(void){};
	virtual ~CExamQuestion(void){};
	void Init();

private:
	CWinThread *m_pTeacherThread;
	CWinThread *m_pStudentThreadArr[STUDENTCOUNT];
	HANDLE m_eventTeacher;
	HANDLE m_eventStudent[STUDENTCOUNT];
	CCriticalSection m_cs;
public:
	UINT InternalTeacherProc();
	UINT InternalStudentProc(int nIndex);
private:
	void OutputLog(char *format,...);
};


 

#include "StdAfx.h"
#include "ExamQuestion.h"

static UINT Teacher_Proc(LPVOID lpParam);
static UINT Student_Proc(LPVOID lpParam);

typedef struct tagThreadParam
{
	CExamQuestion *pExamQuestion;
	int index;
}ThreadParam;

void CExamQuestion::Init()
{
	// TODO: Add extra initialization here
	for(int i=0;i< STUDENTCOUNT;i++)
	{
		m_pStudentThreadArr[i] = NULL;
		m_eventStudent[i] =::CreateEvent(NULL,FALSE,FALSE,NULL);
	}

	m_pTeacherThread = NULL;
	m_eventTeacher=::CreateEvent(NULL,TRUE,FALSE,NULL);

	m_pTeacherThread = AfxBeginThread(Teacher_Proc,this,
		THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
	::ResetEvent(m_eventTeacher);
	
	for(int i = 0;i<STUDENTCOUNT;i++)
	{
		ThreadParam* pParam = new ThreadParam;
		pParam->pExamQuestion = this;
		pParam->index = i; 

		m_pStudentThreadArr[i] = AfxBeginThread(Student_Proc,pParam,
			THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
		::ResetEvent(m_eventStudent[i]);
	}

	for(int i =0;i<STUDENTCOUNT;i++)
	{
		m_pStudentThreadArr[i]->ResumeThread();
	}
	srand(time(0));
	m_pTeacherThread->ResumeThread();
}



各个角色的业务逻辑如下:

static UINT Teacher_Proc(LPVOID lpParam)
{
	CExamQuestion* pExamQuestion = (CExamQuestion *)lpParam;
	return pExamQuestion->InternalTeacherProc();
}

static UINT Student_Proc(LPVOID lpParam)
{
	ThreadParam* pParam =(ThreadParam *)lpParam;
    CExamQuestion* pExamQuestion = pParam->pExamQuestion;
	int nIndex = pParam->index;
	delete pParam;
	pParam = NULL;
	return pExamQuestion->InternalStudentProc(nIndex);
}

//考官线程
UINT CExamQuestion::InternalTeacherProc()
{
	OutputLog("监考老师进入考场\n");
	//等待学生进教室
	::WaitForMultipleObjects(STUDENTCOUNT,m_eventStudent,TRUE,INFINITE);

	OutputLog("监考老师开始发卷\n");
	::Sleep(3000);
	OutputLog("监考老师发卷完毕\n");
	::SetEvent(m_eventTeacher);
    //等待学生交卷
	while(1)
	{
        Sleep(2000);
		DWORD nRet = ::WaitForMultipleObjects(STUDENTCOUNT,m_eventStudent,TRUE,200);
		if(nRet == WAIT_TIMEOUT)
		{
			OutputLog("监考老师正在巡视考场....\n");
			continue;
		}
		else
			break;
	}
	OutputLog("监考老师整理考卷完毕\n");
	Sleep(200);
	OutputLog("监考老师离开教室\n");
	return 0;
}
//考生线程
UINT CExamQuestion::InternalStudentProc(int nIndex)
{
	OutputLog("学生%d进入考场\n",nIndex);
	::SetEvent(m_eventStudent[nIndex]);

	::WaitForSingleObject(m_eventTeacher,INFINITE);//等待老师发卷
	OutputLog("学生%d开始答题\n",nIndex);

	int i = rand()%30;
	Sleep( 1000*(i+1) );
	OutputLog("学生%d答题完毕,交卷\n",nIndex);
	::SetEvent(m_eventStudent[nIndex]);
	Sleep( 50*(i+1));
	OutputLog("学生%d离开教室\n",nIndex);
	return 0;
}

//辅助函数
void CExamQuestion::OutputLog( char *format,... )
{
	char temp[1024]={0};
	va_list arg_ptr;
	va_start(arg_ptr, format);
	vsprintf(temp, format, arg_ptr);
	va_end(arg_ptr);
	
	printf(temp);
}


输出结果如下:

学生0进入考场
学生1进入考场
学生3进入考场
学生2进入考场
学生4进入考场
学生6进入考场
学生8进入考场
学生5进入考场
学生7进入考场
学生9进入考场
监考老师进入考场
监考老师开始发卷
监考老师发卷完毕
学生2开始答题
学生0开始答题
学生1开始答题
学生3开始答题
学生5开始答题
学生7开始答题
学生9开始答题
学生6开始答题
学生4开始答题
学生8开始答题
监考老师正在巡视考场....
监考老师正在巡视考场....
监考老师正在巡视考场....
监考老师正在巡视考场....
监考老师正在巡视考场....
学生2答题完毕,交卷
学生0答题完毕,交卷
学生1答题完毕,交卷
学生3答题完毕,交卷
学生5答题完毕,交卷
学生7答题完毕,交卷
学生9答题完毕,交卷
学生8答题完毕,交卷
学生4答题完毕,交卷
学生6答题完毕,交卷
学生1离开教室
学生2离开教室
学生0离开教室
学生3离开教室
学生5离开教室
学生7离开教室
学生9离开教室
学生4离开教室
学生6离开教室
学生8离开教室
监考老师整理考卷完毕
监考老师离开教室

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值