介绍:
题目来自于开源力量(www.osforce.cn) C语言进阶课程
具体如下:
一间理发店有3位理发师,理发店有沙发,最多坐10人。
3个理发师是三个线程,没有客人时,理发师睡觉。客人上门时,理发师醒过来服务客人。如果理发师都在忙,客人则坐到沙发上等待,如果沙发满了,客人直接离开。
收到关门信号的时候,沙发上的客人直接离开,对于服务到一半的客人,理发师要帮他们剪完头发。
总共两个进程,一个是理发店的,另一个用于发送客人上门和关门命令。
负责发送命令的进程:
界面如下:
事件初始化代码:
//事件名称
const wchar_t szCustomerComeEvent[] = L"szCustomerComeEvent";
const wchar_t szCloseShopEvent[] = L"szCloseShopEvent";
CbarberShopDlg::CbarberShopDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CbarberShopDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
//在对话框类的构造函数中创建事件
m_customerComeEvent = ::CreateEvent(NULL,TRUE,FALSE,szCustomerComeEvent);
m_closeShopEvent = ::CreateEvent(NULL,TRUE,FALSE,szCloseShopEvent);
}
事件触发代码:
//客人上门
void CbarberShopDlg::OnBnClickedCustomerComeButton()
{
::SetEvent(m_customerComeEvent);
::ResetEvent(m_closeShopEvent);
}
//理发店关门
void CbarberShopDlg::OnBnClickedCloseButton()
{
::SetEvent(m_closeShopEvent);
::ResetEvent(m_customerComeEvent);
}
对话框结束清理事件:
CbarberShopDlg::~CbarberShopDlg()
{
//关闭事件
CloseHandle(m_customerComeEvent);
CloseHandle(m_closeShopEvent);
}
理发师实现进程:
//理发师的数量
const int BARBER_COUNT = 3;
//沙发的容量
const int SOFA_CONTAIN_COUNT = 10;
//客人上门的事件名称
const wchar_t szCustomerComeEvent[] = L"szCustomerComeEvent";
//理发店关门的事件名称
const wchar_t szCloseShopEvent[] = L"szCloseShopEvent";
//信号量的名称
const wchar_t szSemaphoreName[] = L"szSemaphoreName";
//沙发
int SOFA[SOFA_CONTAIN_COUNT];
//客人上门事件的句柄
HANDLE g_customerComeEvent = 0;
//理发店关门事件的句柄
HANDLE g_closeShopEvent = 0;
//信号量句柄
HANDLE g_semphore = 0;
//保护沙发的临界区变量
CRITICAL_SECTION g_sofaSection;
DWORD WINAPI BarberProc( LPVOID lpParameter)
{
//获取线程的id
int barberId = *((int*)lpParameter);
//等待客人上门,延时0
if(WAIT_TIMEOUT==::WaitForSingleObject(g_customerComeEvent,0))
{
//客人没有上门,打印 理发师正在睡觉
printf("barber %d is sleeping \n",barberId);
//等待客人上门,永久
::WaitForSingleObject(g_customerComeEvent,INFINITE);
}
HANDLE handles[2] = {g_closeShopEvent,g_semphore};
while(true)
{
//等待关门事件或者客人坐到沙发上
DWORD result = ::WaitForMultipleObjects(2,handles,FALSE,INFINITE);
//信号量
if((WAIT_OBJECT_0+1)==result)
{
//从沙发里面取出一个客户
::EnterCriticalSection(&g_sofaSection);
int customerId = SOFA[0];
assert(customerId>0);
memcpy(SOFA,SOFA+1,(SOFA_CONTAIN_COUNT-1)*sizeof(SOFA[0]));
SOFA[SOFA_CONTAIN_COUNT-1]=0;
::LeaveCriticalSection(&g_sofaSection);
printf("barber %d is working on customer %d \n",barberId,customerId);
Sleep(4000);
}
//关门信号
else if((WAIT_OBJECT_0)==result)
{
printf("barber %d is after work\n",barberId);
return 0;
}
else
{
assert(false);
return 0;
}
}
return 0;
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
//初始化沙发
memset(SOFA,0,sizeof(SOFA));
//初始化临界区
::InitializeCriticalSection(&g_sofaSection);
//创建信号量
g_semphore=::CreateSemaphore(NULL,0,SOFA_CONTAIN_COUNT,szSemaphoreName);
if(0==g_semphore)
{
goto EXIT;
}
//创建事件
g_customerComeEvent = ::CreateEvent(NULL,TRUE,FALSE,szCustomerComeEvent);
if(0==g_customerComeEvent)
{
goto EXIT;
}
g_closeShopEvent = ::CreateEvent(NULL,TRUE,FALSE,szCloseShopEvent);
if(0==g_closeShopEvent)
{
goto EXIT;
}
//创建理发师线程
HANDLE barberThread[BARBER_COUNT] ={0};
int barberId[BARBER_COUNT]={0};
DWORD dword;
for(int i=0;i<BARBER_COUNT;++i)
{
barberId[i] = i+1;
barberThread[i] = ::CreateThread(NULL,0,BarberProc,&barberId[i],0,&dword);
if(0==barberThread[i])
{
goto EXIT;
}
}
HANDLE h[2]={g_closeShopEvent,g_customerComeEvent};
int customerId = 1;
while(true)
{
DWORD result = ::WaitForMultipleObjects(2,h,FALSE,INFINITE);
//客人上门
if((WAIT_OBJECT_0+1)==result)
{
//检查沙发是否已满
if(0!=SOFA[SOFA_CONTAIN_COUNT-1])
{
//满 让客人自己离开
printf("sofa is full \n");
printf("customer %d is leaving \n",customerId);
}
else
{
//未满 将客人放入沙发
::EnterCriticalSection(&g_sofaSection);
for(int i=0;i<SOFA_CONTAIN_COUNT;++i)
{
if(0==SOFA[i])
{
SOFA[i] = customerId;
printf("customer %d is sitting on the sofa \n",customerId);
break;
}
}
::LeaveCriticalSection(&g_sofaSection);
long previousNum = 0;
//
::ReleaseSemaphore(g_semphore,1,&previousNum);
}
Sleep(1000);
customerId++;
}
//关门
else if((WAIT_OBJECT_0)==result)
{
printf("the shop is going to close \n");
::EnterCriticalSection(&g_sofaSection);
for(int i=0;i<SOFA_CONTAIN_COUNT;++i)
{
if(0!=SOFA[i])
{
printf("customer %d is leaving \n",SOFA[i]);
SOFA[i] = 0;
}
}
::LeaveCriticalSection(&g_sofaSection);
//等待理发师线程的结束
::WaitForMultipleObjects(BARBER_COUNT,barberThread,TRUE,INFINITE);
//跳出循环
break;
}
else
{
assert(false);
goto EXIT;
}
}
//善后及异常处理:
EXIT:
//删除临界区
DeleteCriticalSection(&g_sofaSection);
//关闭事件
CloseHandle(g_customerComeEvent);
g_customerComeEvent = 0;
CloseHandle(g_closeShopEvent);
g_closeShopEvent = 0;
//关闭信号量
CloseHandle(g_semphore);
g_semphore = 0;
//关闭线程
for(int i=0;i<BARBER_COUNT;++i)
{
CloseHandle(barberThread[i]);
barberThread[i] = 0;
}
return 0;
}
运行结果:
客人未上门:
收到关门指令: