《Win32多线程程序设计》
Win32 中最具弹性的同步机制就属 events 对象了。 Event 对象是一种核心对象,它的唯一目的就是成为激发状态或未激发状态。这两种状态全由程序来控制,不会成为Wait…() 函数的副作用。
Event 对象之所以有大用途,正是因为它们的状态完全在你掌控之下。Mutexes 和 sem aphores 就不一样了,它们的状态会因为诸如WaitForSingleObject() 之类的函数调用而变化。所以, 你可以精确告诉一个event 对象做什么事,以及什么时候去做。
#include
#include
#include
#include
DWORD WINAPI Thread(void *arg) {
HANDLE hEvent = (HANDLE)arg;
ResetEvent(hEvent); // 设置hEvent为非激发状态
while (1) {
DWORD waitRet = WaitForSingleObject(hEvent, 1000); // 等待hEvent变为激发状态,超时1s
if (WAIT_OBJECT_0 == waitRet) {
printf("%#p被激发,退出此线程\n", hEvent);
break;
}
printf("Thread(%#p), time=%d\n", hEvent, (int)time(NULL));
}
return 0;
}
int main(void) {
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // 创建一个手动控制、初始为非激发状态、未命名的Event对象
HANDLE hThread = CreateThread(NULL, 0, Thread, hEvent, 0, NULL);
Sleep(5000); // 5s后结束Thread线程
SetEvent(hEvent); // 设置hEvent为激发状态
DWORD waitRet = WaitForSingleObject(hThread, INFINITE);
switch (waitRet) {
case WAIT_TIMEOUT: printf("%#p处于非激发状态, 超时\n", hThread); break;
case WAIT_ABANDONED: printf("%#p是一个未释放的Mutex对象\n", hThread); break;
case WAIT_OBJECT_0: printf("%#p处于激发状态\n", hThread); break;
default: printf("WaitForSingleObject(%#p)=%lu,{%ld}\n", hThread, WAIT_FAILED, GetLastError()); break;
}
CloseHandle(hThread);
CloseHandle(hEvent);
return 0;
}
WaitForMultipleObjects 最多可等待64(MAXIMUM_WAIT_OBJECTS)个核心对象。
#include
#include
#include
#include
#define THREAD_NUM 2
DWORD WINAPI Thread(void *arg) {
HANDLE hEvent = (HANDLE)arg;
ResetEvent(hEvent); // 设置hEvent为非激发状态
while (1) {
DWORD waitRet = WaitForSingleObject(hEvent, 1000); // 等待hEvent变为激发状态,超时1s
if (WAIT_TIMEOUT != waitRet) {
printf("WaitForSingleObject(%#p)=%lu,退出此线程\n", hEvent, waitRet);
break;
}
printf("Thread(%#p), time=%d\n", hEvent, (int)time(NULL));
}
return 0;
}
int main(void) {
HANDLE hThreadArray[THREAD_NUM], hEventArray[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i++) {
hEventArray[i] = CreateEvent(NULL, TRUE, FALSE, NULL); // 创建一个手动控制、初始为非激发状态、未命名的Event对象
hThreadArray[i] = CreateThread(NULL, 0, Thread, hEventArray[i], 0, NULL);
}
for (int i = 0; i < THREAD_NUM; i++) {
Sleep(3000); // 每隔3s终止一个线程
SetEvent(hEventArray[i]); // 设置一个Event对象为激发状态
}
DWORD waitRet = WaitForMultipleObjects(THREAD_NUM, hThreadArray, TRUE, INFINITE); // 等待所有线程,无限超时
switch (waitRet) {
case WAIT_TIMEOUT: printf("存在对象处于非激发状态, 超时\n"); break;
case WAIT_ABANDONED_0: printf("所有对象处于激发状态,但其中有未释放的Mutex对象\n"); break;
case WAIT_OBJECT_0: printf("所有对象处于激发状态\n"); break;
default: printf("WaitForMultipleObjects()=%lu,{%ld}\n", WAIT_FAILED, GetLastError()); break;
}
for (int i = 0; i < THREAD_NUM; i++) {
CloseHandle(hThreadArray[i]);
CloseHandle(hEventArray[i]);
}
return 0;
}
BOOL xxx::OnInitDialog()
{
CDialog::OnInitDialog();
m_picDirHandle = (HANDLE)_beginthread(&CheckPicDirFunc, 1024 * 1024 * 10, this);
m_photoSocketHandle = (HANDLE)_beginthread(&PhotoSocketFunc, 1024 * 1024 * 10, this);
m_dirEvtHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
m_sockEvtHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void xxx::OnClose()
{
SetEvent(m_dirEvtHandle);
SetEvent(m_sockEvtHandle);
HANDLE funcHandle[2] = {m_picDirHandle, m_photoSocketHandle};
DWORD dwRet = WaitForMultipleObjects(ARRAY_LENGTH(funcHandle), funcHandle, FALSE, INFINITE);
switch (dwRet) {
case WAIT_OBJECT_0:
LOG("WaitForMultipleObjects()---CheckPicDirFunc线程安全退出");
case WAIT_OBJECT_0 + 1:
LOG("WaitForMultipleObjects()---PhotoSocketFunc线程安全退出");
break;
default:
LOG("WaitForMultipleObjects()---释放资源失败");
break;
}
CloseHandle(m_dirEvtHandle);
CloseHandle(m_sockEvtHandle);
CDialog::OnClose();
}
void xxx::PhotoSocketFunc(void *p_para) {
xxx *dlg = (xxx *)p_para;
ResetEvent(dlg->m_sockEvtHandle);
while (TRUE) {
if (WAIT_OBJECT_0 == WaitForSingleObject(dlg->m_sockEvtHandle, 0)) {
LOG("PhotoSocketFunc() Exit\n");
break;
}
printf("thread test photo\n");
Sleep(10);
}
}
void xxx::CheckPicDirFunc(void *p_para) {
xxx *dlg = (xxx *)p_para;
ResetEvent(dlg->m_dirEvtHandle);
while (TRUE) {
if (WAIT_OBJECT_0 == WaitForSingleObject(dlg->m_dirEvtHandle, 1000 * 60 * 60 * 2)) { // 超时2小时
LOG("CheckPicDirFunc() Exit\n");
break;
}
printf("thread test dir\n");
Sleep(10);
}
}