讨论

一两种方式建立,一种为自动重置,在其余线程使用WaitForSingleObject等待到事件对象变为有信号后该事件对象自动又变为无信号状态,一种为人工重置在其余线程使用WaitForSingleObject等待到事件对象变为有信号后该事件对象状态不变。例若有多个线程都在等待一个线程运行结束,咱们就可使用人工重置事件,在被等待的线程结束时设置该事件为有信号状态,这样其余的多个线程对该事件的等待都会成功(由于该事件的状态不会被自动重置)。事件相关的API以下: 

建立事件对象:
HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes,// 安全属性,NULL表示使用默认的安全描述
  BOOL bManualReset,  // 是否为人工重置
  BOOL bInitialState, // 初始状态是否为有信号状态
  LPCTSTR lpName      // 名字
);
打开事件对象:
HANDLE OpenEvent(
  DWORD dwDesiredAccess,  // 存取方式
  BOOL bInheritHandle,    // 是否可以被继承
  LPCTSTR lpName          // 名字
);
设置事件为无信号状态:
BOOL ResetEvent(
  HANDLE hEvent   // 句柄
);
设置事件有无信号状态:
BOOL SetEvent(
  HANDLE hEvent   // 句柄
);
关闭事件对象:
BOOL CloseHandle(
  HANDLE hObject   // 句柄
);

下面的代码演示了自动重置和人工重置事件在使用中的不一样效果: 

DWORD threadA(void* pD)
{
int iID=(int)pD;
//在内部从新打开
HANDLE hCounterIn=OpenEvent(EVENT_ALL_ACCESS,FALSE,"sam sp 44");

printf("\tthread %d begin\n",iID);
//设置成为有信号状态
Sleep(1000);
SetEvent(hCounterIn);
Sleep(1000);
printf("\tthread %d end\n",iID);
CloseHandle(hCounterIn);
return 0;
}

DWORD threadB(void* pD)
{//等待threadA结束后在继续执行
int iID=(int)pD;
//在内部从新打开
HANDLE hCounterIn=OpenEvent(EVENT_ALL_ACCESS,FALSE,"sam sp 44");

if(WAIT_TIMEOUT == WaitForSingleObject(hCounterIn,10*1000))
{
printf("\t\tthread %d wait time out\n",iID);
}
else
{
printf("\t\tthread %d wait ok\n",iID);
}
CloseHandle(hCounterIn);
return 0;
}

//in main function
{
HANDLE hCounter=NULL;
if( (hCounter=OpenEvent(EVENT_ALL_ACCESS,FALSE,"sam sp 44"))==NULL)
{
//若是没有其余进程建立这个事件,则从新建立,该事件为人工重置事件
hCounter = CreateEvent(NULL,TRUE,FALSE,"sam sp 44");
}

//建立线程
HANDLE hThread[3];
printf("test of manual rest event\n");
CWinThread* pT1=AfxBeginThread((AFX_THREADPROC)threadA,(void*)1);
CWinThread* pT2=AfxBeginThread((AFX_THREADPROC)threadB,(void*)2);
CWinThread* pT3=AfxBeginThread((AFX_THREADPROC)threadB,(void*)3);
hThread[0]=pT1->m_hThread;
hThread[1]=pT2->m_hThread;
hThread[2]=pT3->m_hThread;
//等待线程结束
WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
//关闭句柄
CloseHandle(hCounter);

if( (hCounter=OpenEvent(EVENT_ALL_ACCESS,FALSE,"sam sp 44"))==NULL)
{
//若是没有其余进程建立这个事件,则从新建立,该事件为自动重置事件
hCounter = CreateEvent(NULL,FALSE,FALSE,"sam sp 44");
}
//建立线程
printf("test of auto rest event\n");
pT1=AfxBeginThread((AFX_THREADPROC)threadA,(void*)1);
pT2=AfxBeginThread((AFX_THREADPROC)threadB,(void*)2);
pT3=AfxBeginThread((AFX_THREADPROC)threadB,(void*)3);
hThread[0]=pT1->m_hThread;
hThread[1]=pT2->m_hThread;
hThread[2]=pT3->m_hThread;
//等待线程结束
WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
//关闭句柄
CloseHandle(hCounter);
}

从执行结果中咱们能够看到在第二次执行时因为使用了自动重置事件threadB中只有一个线程可以等待到threadA中释放的事件对象。 

在处理多进程/线程的同步问题时必需要当心避免发生死锁问题,好比说如今有两个互斥量A和B,两个线程tA和tB,他们在执行前都须要获得这两个互斥量,但如今这种状况发生了,tA拥有了互斥量A,tB拥有了互斥量B,但它们同时都在等待拥有另外一个互斥量,这时候显然谁也不可能获得本身但愿的资源。这种互相拥有对方所拥有的资源并且都在等待对方拥有的资源的状况就称为死锁。关于这个问题更详细的介绍请参考其余参考书。 

在MFC中对于各类同步对象都提供了相对应的类

在这些类中封装了上面介绍的对象建立,打开,控制,删除功能。可是若是要使用等待功能则须要使用另外两个类:CSingleLock和CMultiLock。这两个类中封装了WaitForSingleObject和WaitForMultipleObjects函数。若是你们觉的须要能够看看这些类的定义,我想经过上面的介绍能够很容易理解,可是在对象同步问题上我以为使用API函数比使用MFC类更为直观和方便。安全

相关文章
相关标签/搜索