一,WaitForSingleObject的用法
1.WaitForSingleObject 的用法
DWORD WaitForSingleObject( HANDLE hHandle, DWORDdwMilliseconds );
参数 hHandle 是一个事件的句柄,第二个参数 dwMilliseconds 是时间间隔。如果时间是有信号状态返回WAIT_OBJECT_0 ,如果时间超过 dwMilliseconds 值但时间事件还是无信号状态则返回 WAIT_TIMEOUT 。
hHandle 可以是下列对象的句柄:Change notification Console input Event Job Memory resource notification Mutex Process Semaphore Thread Waitable timerWaitForSingleObject 函数用来检测 hHandle 事件的信号状态,当函数的执行时间超过 dwMilliseconds 就返回,但如果参数 dwMilliseconds 为 INFINITE 时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到 WaitForSingleObject 有返回直才执行后面的代码。在这里举个例子:
先创建一个全局 Event 对象 g_event:
CEvent g_event;
在程序中可以通过调用 CEvent::SetEvent 设置事件为有信号状态。
下面是一个线程函数 MyThreadPro()
UINT CFlushDlg::MyThreadProc( LPVOID pParam )
{WaitForSingleObject(g_event,INFINITE);
For(;;) { ………… .}
return 0; }在这个线程函数中只有设置 g_event 为有信号状态时才执行下面的 for 循环,因为 g_event 是全局变量,所以我们可以在别的线程中通过 g_event. SetEvent 控制这个线程。
还有一种用法就是我们可以通过 WaitForSingleObject 函数来间隔的执行一个线程函数的函数体
UINT CFlushDlg::MyThreadProc( LPVOID pParam )
{ while(WaitForSingleObject(g_event,MT_INTERVAL)!=WAIT_OBJECT_0) { ……………… } return 0;}在这个线程函数中可以可以通过设置 MT_INTERVAL 来控制这个线程的函数体多久执行一次,当事件为无信号状态时函数体隔 MT_INTERVAL 执行一次,当设置事件为有信号状态时,线程就执行完毕了。
程序举例:1、创建对话框应用程序,项目名称为MyTestThread2、添加按钮,命名为启动和停止,在对话框中增加编辑框,ID为IDC_TIME,3、增加成员变量,HANDLE m_hThread[2],此为线程的句柄;4、定义全局变量,用来控制线程的运行与否; volatile BOOL m_ThreadRun[2];5、增加全局事件对象,用来监控线程,控制线程是否运行。 CEvent event; 注意:4、5定义的对象,必须在.cpp文件中定义;6、声明回调函数。回调函数必须是全局函数或静态函数。声明方式如下:void ThreadFunc1(LPVOID pParam);void ThreadFunc2(LPVOID pParam); 回调函数的实现如下:void ThreadFunc1(LPVOID pParam){ CTime time; CString strTime; event.ResetEvent(); m_ThreadRun[0] = true; m_ThreadRun[1] = true; DWORD ThreadID = ::GetCurrentThreadId(); while(m_ThreadRun[0]) { time = CTime::GetCurrentTime(); strTime = time.Format("%H:%M:%S"); CMyTestThreadDlg* pDlg = (CMyTestThreadDlg*)pParam; pDlg->SetDlgItemText(IDC_TIME,strTime); Sleep(1000); }}void ThreadFunc2(LPVOID pParam){ CTime time; CString strTime; DWORD ThreadID = ::GetCurrentThreadId();//event为有信号状态,则下边的函数执行后,该线程则开始运行,如果event为无信号状态,则下边的函数执行//后,该线程处于等待状态,直到有信号才开始运行; ::WaitForSingleObject(event,INFINITE); while(m_ThreadRun[1]) { time = CTime::GetCurrentTime(); strTime = time.Format("%H:%M:%S"); CMyTestThreadDlg* pDlg = (CMyTestThreadDlg*)pParam; pDlg->SetDlgItemText(IDC_TIME,"OK"); Sleep(1000); ::WaitForSingleObject(event,INFINITE); }}7、定义保存线程ID的成员变量:DWORD m_ThreadID[2];8、对启动和停止按钮增加消息响应函数,如下:void CMyTestThreadDlg::OnBnClickedOk(){ // TODO: 在此添加控件通知处理程序代码 m_hThread[0] = ::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFunc1,this,0,&m_ThreadID[0]); m_hThread[1] = ::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFunc2,this,0,&m_ThreadID[1]); GetDlgItem(IDC_BUTTON1)->EnableWindow(false); GetDlgItem(IDC_BUTTON2)->EnableWindow(true);}void CMyTestThreadDlg::OnBnClickedCancel(){ m_ThreadRun[0] = false; event.SetEvent(); GetDlgItem(IDC_BUTTON1)->EnableWindow(true); GetDlgItem(IDC_BUTTON2)->EnableWindow(false);}编译运行,设置断点,可以查看运行情况。二,ReleaseMutex用法放在 WaitForSingleObject后面 直到不再需要保护参数为止
如 要保护全局 int a; 线程1 { WaitforsingleObject....... //等待获得对a的写的权利 a++ //保护部分 ReleaseMutex...... //不需要保护了 允许其它线程写a } 线程2 { WaitforsingleObject....... //等待获得对a的写的权利 a++ //保护部分 ReleaseMutex...... //不需要保护了 允许其它线程写a }