20170710Windows11_2_事件内核对象

来源:互联网 发布:angularjs.js 2.0下载 编辑:程序博客网 时间:2024/06/05 11:21

内核对象——事件内核对象:

事件内核对象(1)

1:线程的同步:
#include <cstdio>#include <tchar.h>#include <windows.h>#include <process.h>int *g_pNum = nullptr;bool g_Using = false;void Entry()//原子操作,进入锁{while (InterlockedExchange((long*)&g_Using, true) == true){Sleep(0);}}void Leave()//原子操作,离开锁。{InterlockedExchange((long*)&g_Using, false);}void ThreadPrintf(TCHAR* strText){Entry();_tprintf(strText);//非线程安全的,需要加锁。Leave();}unsigned __stdcall StartThread(void* lParam){ThreadPrintf(TEXT("Enter StartThread\r\n"));g_pNum = new int(0);Sleep(1000);ThreadPrintf(TEXT("End StartThread\r\n"));return 0;}unsigned __stdcall EndThread(void* lParam){ThreadPrintf(TEXT("Enter EndThread\r\n"));HANDLE hStart = lParam;ThreadPrintf(TEXT("Waiting EndThread\r\n"));WaitForSingleObject(hStart, INFINITE); //会使EndThread处于不可调度,节约资源。delete g_pNum;ThreadPrintf(TEXT("End EndThread\r\n"));return 0;}int main(){HANDLE hStart = (HANDLE)_beginthreadex(nullptr, 0, StartThread, nullptr, 0, nullptr);//Sleep(1000);//用于控制先后顺序HANDLE hEnd = (HANDLE)_beginthreadex(nullptr, 0, EndThread, hStart, 0, nullptr);WaitForSingleObject(hEnd, INFINITE);return 0;}

2:事件内核对象也是一种用于线程进程同步的内核对象,它可以自动重置也可以手动重置。最为重要的参数是Signal参数,事件内核对象创建的时候可以使用那个CreateEvent。创建事件内核对象的时候,会设置重置的方式,FALSE为自动重置,TRUE为手动重置。

事件内核对象(2)——自动及手动及信号及No信号:

1:很显然,Thread和Process的内核对象并不是专门拿来做同步的,只是里面有Signal这个成员了,可以对此进行Wait的操作,事件内核对象是一个较为特殊的内核对象,他并非一个实体,里面也有使用计数,Signal状态,我们可以自动或者手动设置状态。
2:使用CreateEvent,CreateEventEx(XP下无法使用)。
CreateEventW(    _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes,//安全指针,一般传nullptr    _In_ BOOL bManualReset,//是否为人为置位。    _In_ BOOL bInitialState,//初始化状态。TRUER为有信号状态    _In_opt_ LPCWSTR lpName//事件内核对象名称。    );


3:其他进程仅能通过事件内核对象的名称来访问这个事件内核对象,如果事件内核对象内有设置名称就为匿名事件内核对象,这样的内核对象只能在当前进程里面使用。
#include <windows.h>int main(){HANDLE hEvent = CreateEvent(nullptr, TRUE, TRUE, nullptr);//此事件内核对象只能在本进程里面使用WaitForSingleObject(hEvent, INFINITE);//会等待一个内核对象变为Signal状态。ResetEvent(hEvent);// 会使这个内核对象变为no Signal状态。WaitForSingleObject(hEvent, INFINITE);//手动重置,不Reset就会直接通过,Reset就会阻塞在这里//如果为自动重置,那么WaitForSingleObject就会改变内核对象里面的Signal状态,下一次WaitForSingleObject就会阻塞。CloseHandle(hEvent);return 0;}

4:自动重置状态会导致WaitForSingleObject会改变事件内核对象里面的Signal状态,如果为手动重置,那么在不掉用ResetEvent的情况下,内核对象会一直处于有信号状态,WaitForSingleObject也不可以改变其Signal状态。

事件内核对象(3)——作业:

1:CreateEventEx:参数含义与CreateEvent有所不同。
CreateEventExW(    _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes,//权限访问符    _In_opt_ LPCWSTR lpName,//内核对象名称    _In_ DWORD dwFlags,//CREATE_EVENT_INITIAL_SET或者CREATE_EVENT_MANUAL_RESET。代表有信号状态,手动的。不传递这个参数,就为noSignal的自动的。    _In_ DWORD dwDesiredAccess//权限设置。    );

2:CreateEvent是默认全权限的,可以做任何事情,而CreateEventEx可以设置里面的权限。主要用于设置对Event操作的权限。也有读权限,写权限等:
    读权限:只能来WaitForSignalObject,写权限:可以Set和Reset内核对象。SetEvent可以使之变为有信号状态,ResetEvent可以使之变为无信号状态。

事件内核对象(4)——练习:

1:我们在word里面编辑的时候,会发现其有字数统计(会有延后),拼写检查等等,输入网址他会自动设置为连接(渲染),事实上,他是使用的多线程来实现的。
void CEventDemoDlg::OnSetfocusEditText(){// TODO:  在此添加控件通知处理程序代码if (m_hThreadGetCount == INVALID_HANDLE_VALUE){m_hThreadGetCount = (HANDLE)_beginthreadex(nullptr, 0, ThreadGetCount, this, 0, nullptr);}if (m_hIsUrl == INVALID_HANDLE_VALUE){m_hIsUrl = (HANDLE)_beginthreadex(nullptr, 0, ThreadIsUrl, this, 0, nullptr);}SINGLE_LIST_ENTRY hEventSignal;SetEvent(m_hEvent);//Event变为有信号}void CEventDemoDlg::OnKillfocusEditText(){// TODO:  在此添加控件通知处理程序代码ResetEvent(m_hEvent);//无信号3}unsigned __stdcall CEventDemoDlg::ThreadGetCount(void* lParam){CEventDemoDlg* pThis = (CEventDemoDlg*)lParam;static CString strText;size_t nCount = 0;while (TRUE){WaitForSingleObject(pThis->m_hEvent, INFINITE);pThis->GetDlgItemText(IDC_EDIT_TEXT, strText);nCount = strText.GetLength();pThis->SetDlgItemInt(IDC_STATIC_COUNT, nCount);Sleep(50);}return 0;}unsigned __stdcall CEventDemoDlg::ThreadIsUrl(void* lParam){CEventDemoDlg* pThis = (CEventDemoDlg*)lParam;WaitForSingleObject(pThis->m_hEvent, INFINITE);return 0;}

2:上面是使用事件内核对象和多线程统计字数的一个例子。