事件对象 CreateEvent
为了实现线程间的同步,不应该使用人工重置的事件对象,而应该使用自动重置的事件对象。
g_hEvent = CreateEvent(NULL,FALSE,TRUE,NULL);
注意区分人工重置事件对象和自动重置事件对象。
当人工重置的事件对象得到通知时,等待该事件对象的所有线程均变为可调度线程,
操作系统不会将该事件对象设置为无信息状态,需要显式地调用ResetEvent函数将其设置为无信号状态,
否则该对象一直是有信号状态。
当一个自动重置的事件对象得到通知时,等待该事件对象的线程中只有一个线程变为可调度线程,
同时操作系统会将该事件对象设置无信号状态,这样,当对所保护的代码的执行完成后,需要调用
SetEvent函数将该事件对象设置为有信号状态。
CreateEvent
The CreateEvent function creates a named or unnamed event object.
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
// pointer to security attributes
BOOL bManualReset, // flag for manual-reset event
BOOL bInitialState, // flag for initial state
LPCTSTR lpName // pointer to event-object name
);
Parameters
lpEventAttributes
Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpEventAttributes is NULL, the handle cannot be inherited.
Windows NT: The lpSecurityDescriptor member of the structure specifies a security descriptor for the new event. If lpEventAttributes is NULL, the event gets a default security descriptor.
bManualReset
Specifies whether a manual-reset or auto-reset event object is created. If TRUE, then you must use the ResetEvent function to manually reset the state to nonsignaled. If FALSE, the system automatically resets the state to nonsignaled after a single waiting thread has been released.
bInitialState
Specifies the initial state of the event object. If TRUE, the initial state is signaled; otherwise, it is nonsignaled.
lpName
Pointer to a null-terminated string specifying the name of the event object. The name is limited to MAX_PATH characters and can contain any character except the backslash path-separator character (\). Name comparison is case sensitive.
If lpName matches the name of an existing named event object, this function requests EVENT_ALL_ACCESS access to the existing object. In this case, the bManualReset and bInitialState parameters are ignored because they have already been set by the creating process. If the lpEventAttributes parameter is not NULL, it determines whether the handle can be inherited, but its security-descriptor member is ignored.
If lpName is NULL, the event object is created without a name.
If lpName matches the name of an existing semaphore, mutex, waitable timer, job, or file-mapping object, the function fails and the GetLastError function returns ERROR_INVALID_HANDLE. This occurs because these objects share the same name space.
Return Values
If the function succeeds, the return value is a handle to the event object. If the named event object existed before the function call, the function returns a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS.
If the function fails, the return value is NULL. To get extended error information, call GetLastError.
#include <windows.h> #include <iostream> using namespace std; DWORD WINAPI MyThreadProc1(LPVOID lpParameter); //thread data DWORD WINAPI MyThreadProc2(LPVOID lpParameter); DWORD WINAPI MyThreadProc3(LPVOID); //thread data DWORD WINAPI MyThreadProc4(LPVOID); int tickets=100; HANDLE hEvent; int main(){ DWORD tid1=0,tid2=0; //HANDLE handle = CreateThread(NULL,0,MyThreadProc,NULL,0,&tid); HANDLE handle1 = CreateThread(NULL,0,MyThreadProc1,NULL,CREATE_SUSPENDED ,&tid1); HANDLE handle2 = CreateThread(NULL,0,MyThreadProc2,NULL,CREATE_SUSPENDED ,&tid2); ResumeThread(handle1); ResumeThread(handle2); /* int i = 0; for(;i<100;i++) cout<<"Main thread is running"<<endl; */ hEvent = CreateEvent(NULL,FALSE,TRUE,NULL); Sleep(8000); CloseHandle(hEvent); CloseHandle(handle1); CloseHandle(handle2); cout<< "SubThread1 ID:" << hex << uppercase<< tid1 << endl; cout<< "SubThread2 ID:" << hex << uppercase<< tid2 << endl; /* cout<<"**************************************************"<<endl; HANDLE handle3 = CreateThread(NULL,0,MyThreadProc3,NULL,0 ,&tid1); HANDLE handle4 = CreateThread(NULL,0,MyThreadProc4,NULL,0 ,&tid2); CloseHandle(handle3); CloseHandle(handle4); */ system("pause"); return 0; } /* WAIT_OBJECT_0 The state of the specified object is signaled. WAIT_TIMEOUT The time-out interval elapsed, and the object's state is nonsignaled. */ DWORD WINAPI MyThreadProc1( LPVOID lpParameter // thread data ) { //Sleep(20); //int i=0; while(TRUE){ //WaitForSingleObject(hMutex,INFINITE); DWORD dwCode = WaitForSingleObject(hEvent,INFINITE); //ResetEvent(hEvent); if(dwCode == WAIT_TIMEOUT){ cout<<endl<<"子线程1 等待超时"<<endl; continue; } if(tickets){ cout<<"子线程1卖票:"<<tickets<<endl; --tickets; Sleep(15); SetEvent(hEvent); } else { SetEvent(hEvent); break; } } return 1; } DWORD WINAPI MyThreadProc2( LPVOID lpParameter // thread data ) { while(TRUE){ //WaitForSingleObject(hMutex,INFINITE); DWORD dwCode = WaitForSingleObject(hEvent,INFINITE); //ResetEvent(hEvent); if(dwCode == WAIT_TIMEOUT){ cout<<endl<<"子线程2 等待超时"<<endl; continue; } if(tickets){ cout<<"子线程2卖票:"<<tickets<<endl; --tickets; Sleep(15); SetEvent(hEvent); } else { SetEvent(hEvent); break; } } return 1; } /* DWORD WINAPI MyThreadProc3( LPVOID lpParameter ) { DWORD dwCode = WaitForSingleObject(hMutex,5); if(dwCode == WAIT_TIMEOUT){ cout<<endl<<"子线程3 等待超时"<<endl; } else if(dwCode == WAIT_ABANDONED){ cout<<endl<<"子线程3 WAIT_ABANDONED"<<endl; } cout<<"子线程3运行"<<endl; return 1; } DWORD WINAPI MyThreadProc4( LPVOID lpParameter ) { DWORD dwCode = WaitForSingleObject(hMutex,5); if(dwCode == WAIT_TIMEOUT){ cout<<endl<<"子线程4 等待超时"<<endl; } else if(dwCode == WAIT_ABANDONED){ cout<<endl<<"子线程4 WAIT_ABANDONED"<<endl; } cout<<"子线程4运行"<<endl; return 1; } */