34win32编程基础——线程安全之事件
事件:
HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPTSTR lpName );
前边学习了,临界区、互斥体,为什么要学事件呢?
学习要带着疑问去学习,因此不管是临界区还是互斥体只能解决互斥问题,解决不了同步问题。
事件可以控制线程简单的交替执行(简单同步),复杂同步后边学习信号量。
CreateEvent 最重要的是第2个和第3个参数。
CreateEvent(NULL,TRUE,xxx,"XYZ") TRUE表示,当第一个线程等到事件的时候,如果不使用ResetEvent函数手动把把事件变为未通知状态,那么当第一个等待事件的线程并不会把等待的已通知事件状态改为未通知状态,而是会传递下去,那么别的等待线程也可以等到这个事件。直到某个线程使用ResetEvent函数把事件状态改为未通知状态。
CreateEvent(NULL,FALSE,xxx,"XYZ") FALSE表示,当1个等待事件之后,系统自动的把等待的已通知事件状态变为未通知状态,那么别的线程就会继续等待下去。
SetEvent(Hevent)把事件变为已通知状态
ResetEvent(Hevent)把事件变为未通知状态
CreateEvent(NULL,XXX,TRUE,"XYZ") TRUE表示,事件刚开始为已通知状态。
CreateEvent(NULL,XXX,FALSE,"XYZ") FALSE表示,事件刚开始为未通知状态。
示例如下:
#include <Windows.h>
#include "resource.h"
#include <stdio.h>
HANDLE hEvent;
HWND hDialog;
int EditMem[3];
DWORD WINAPI ThreadEditProc(
__in LPVOID lpParameter
){
TCHAR sz[20];
WaitForSingleObject(hEvent,-1);//第二个参数为FALSE,当第一个线程Wait到的时候,系统自动改变事件状态为未通知状态,其他线程就等不到。
//第二个参数为TRUE,当第一个线程Wait到的时候,需要使用ResetEvent手动改为未通知状态,如果不使用ResetEvent那么事件一直都是已通知状态
GetDlgItemText(hDialog,IDC_EDIT_ALL,sz,20);
SetDlgItemText(hDialog,EditMem[int(lpParameter)],sz);
return 0;
};
DWORD WINAPI ThreadMainProc(
__in LPVOID lpParameter
){
hEvent = CreateEvent(NULL,FALSE,FALSE,TEXT("xyz"));//刚开始为未通知状态,并且系统自动变为未通知状态
//hEvent = CreateEvent(NULL,TRUE,FALSE,TEXT("xyz"));//刚开始为未通知状态,需要使用手动变为未通知状态
HANDLE hThread[3];
hThread[0] = CreateThread(NULL,NULL,ThreadEditProc,(LPVOID)0,0,NULL);
hThread[1] = CreateThread(NULL,NULL,ThreadEditProc,(LPVOID)1,0,NULL);
hThread[2] = CreateThread(NULL,NULL,ThreadEditProc,(LPVOID)2,0,NULL);
SetDlgItemText(hDialog,IDC_EDIT_ALL,TEXT("1000"));
Sleep(3000);
SetEvent(hEvent);//事件变为已通知状态
WaitForMultipleObjects(3,hThread,TRUE,-1);
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
CloseHandle(hThread[2]);
CloseHandle(hEvent);
return 0;
};
BOOL CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam,
LPARAM lParam){
switch(uMsg)
{
case WM_COMMAND:
{
WORD Id=LOWORD(wParam);
WORD EventId = HIWORD(wParam);
switch(Id)
{
case IDC_BUTTON_BEGIN:
{
HANDLE HMain = CreateThread(NULL,NULL,ThreadMainProc,(LPVOID)hwndDlg,0,NULL);
}
default:
{
return FALSE;
}
}
return 0;
}
case WM_CLOSE:
{
EndDialog(hwndDlg,0);
return 0;
}
case WM_INITDIALOG:
{
hDialog = hwndDlg;
EditMem[0] = IDC_EDIT_H1;
EditMem[1] = IDC_EDIT_H2;
EditMem[2] = IDC_EDIT_H3;
SetDlgItemText(hwndDlg,IDC_EDIT_ALL,TEXT("0"));
SetDlgItemText(hwndDlg,IDC_EDIT_H1,TEXT("0"));
SetDlgItemText(hwndDlg,IDC_EDIT_H2,TEXT("0"));
SetDlgItemText(hwndDlg,IDC_EDIT_H3,TEXT("0"));
return 0;
}
}
return FALSE;
};
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG_MAIN),NULL,DialogProc);
return 0;
}

当点击开始的时候,第1个编辑框先做完加法之后,下边的3个编辑框才能取出来数据。
当使用
hEvent = CreateEvent(NULL,FALSE,FALSE,TEXT("xyz"));//刚开始为未通知状态,并且系统自动变为未通知状态
当第一个等待事件的线程,等到事件之后,事件变为未通知状态,其他线程就会一直阻塞下去。

当使用
hEvent = CreateEvent(NULL,TRUE,FALSE,TEXT("xyz"))
当第一个线程等到事件之后,并不改变事件的状态,其他2个线程也会等到,因此点击开始之后,3个编辑框都会变为1000.

使用事件实现同步和互斥:
#include <Windows.h>
#include "resource.h"
#include <stdio.h>
HANDLE hEvent;
HWND hDialog;
int EditMem[3];
DWORD WINAPI ThreadEditProc(
__in LPVOID lpParameter
){
TCHAR sz[20];
WaitForSingleObject(hEvent,-1);//第二个参数为FALSE,当第一个线程Wait到的时候,系统自动改变事件状态为未通知状态,其他线程就等不到。
//第二个参数为TRUE,当第一个线程Wait到的时候,需要使用ResetEvent手动改为未通知状态,如果不使用ResetEvent那么事件一直都是已通知状态
GetDlgItemText(hDialog,IDC_EDIT_ALL,sz,20);
SetDlgItemText(hDialog,EditMem[int(lpParameter)],sz);
Sleep(2000);
SetEvent(hEvent);
return 0;
};
DWORD WINAPI ThreadMainProc(
__in LPVOID lpParameter
){
hEvent = CreateEvent(NULL,FALSE,FALSE,TEXT("xyz"));//刚开始为未通知状态,并且系统自动变为未通知状态
//hEvent = CreateEvent(NULL,TRUE,FALSE,TEXT("xyz"));//刚开始为未通知状态,需要使用手动变为未通知状态
HANDLE hThread[3];
hThread[0] = CreateThread(NULL,NULL,ThreadEditProc,(LPVOID)0,0,NULL);
hThread[1] = CreateThread(NULL,NULL,ThreadEditProc,(LPVOID)1,0,NULL);
hThread[2] = CreateThread(NULL,NULL,ThreadEditProc,(LPVOID)2,0,NULL);
SetDlgItemText(hDialog,IDC_EDIT_ALL,TEXT("1000"));
Sleep(3000);
SetEvent(hEvent);//事件变为已通知状态
WaitForMultipleObjects(3,hThread,TRUE,-1);
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
CloseHandle(hThread[2]);
CloseHandle(hEvent);
return 0;
};
BOOL CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam,
LPARAM lParam){
switch(uMsg)
{
case WM_COMMAND:
{
WORD Id=LOWORD(wParam);
WORD EventId = HIWORD(wParam);
switch(Id)
{
case IDC_BUTTON_BEGIN:
{
HANDLE HMain = CreateThread(NULL,NULL,ThreadMainProc,(LPVOID)hwndDlg,0,NULL);
}
default:
{
return FALSE;
}
}
return 0;
}
case WM_CLOSE:
{
EndDialog(hwndDlg,0);
return 0;
}
case WM_INITDIALOG:
{
hDialog = hwndDlg;
EditMem[0] = IDC_EDIT_H1;
EditMem[1] = IDC_EDIT_H2;
EditMem[2] = IDC_EDIT_H3;
SetDlgItemText(hwndDlg,IDC_EDIT_ALL,TEXT("0"));
SetDlgItemText(hwndDlg,IDC_EDIT_H1,TEXT("0"));
SetDlgItemText(hwndDlg,IDC_EDIT_H2,TEXT("0"));
SetDlgItemText(hwndDlg,IDC_EDIT_H3,TEXT("0"));
return 0;
}
}
return FALSE;
};
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG_MAIN),NULL,DialogProc);
return 0;
}
这样线程会一个一个依次读取第一个编辑框中的值。

浙公网安备 33010602011771号