怎样使用WIN32的事件(Event)核心对象----How to use WIN32 Event Kernel Object(源码下载)

1、说明
         事件的同步是一个很麻烦的区域,虽然有很多方法去处理它。市面上也有很多书和文章介绍怎样避免多线程产生的噩梦。通过处理这些噩梦,我渐渐理解了WIN32的事件(Win32 Kernel objects)。在最初时,我不能理解怎么通过在线程中使用全局变量来使用全局的核心事件;后来我理解后,我发现这个是很容易来使用的。这里,我将解释Win32事件中关于自动和手动设置重置事件的内容。

2、关于Win32 Events
         Win32 Events也像其他的核心对象一样在跨进程是可利用的。一个Win32事件就是一个状态机,它的生命期间基于2种状态--Signaled state(激活状态,有信号状态) and Non Signaled state(为激活状态,无信号状态)。   一个事件处于激活状态,意味着这个事件可以停止正在等待这个激活信号的线程;而一个处于非激活状态的,意味着它不能停止这个正在等待这个事件信号的线程。

3、自动重置Win32事件
         自动重置事件----它保证关闭单线程(这个单线程正处于等待这个事件的发生,然后返回到非激活状态);如果有多个线程正在同时等待这个事件信号,这些线程是随机触发关闭的。
         一些Win32事件创建和使用的API:

CreateEvent();  //创建事件的API
CreateThread(); //创建线程的API

//等待一个事件(信号)的API
WaitForSingleObject();
WaitForMultipleObject();

OpenHandle();   
//获得一个事件句柄的API
SetEvent();     //使一个事件处于激活状态的API
ResetEvent();   //使一个事件处于非激活状态的API
CloseHandle();  //关闭事件句柄的API

         下面是自动重置事件的相关代码(VS2010):
#include <Windows.h>
#include 
<iostream>

using namespace std;

// 需要激活的线程
DWORD WINAPI ThreadFun(LPVOID n)
{
    cout 
<< "Thread Instantiated" << endl;

    
// 获得激活事件的句柄(以"MyEvent"为标识)
    HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, false, (LPCWSTR)"MyEvent");  //  (LPCWSTR)在vs2010,不加入的话会报错
    if (!hEvent)
    
{
        
return -1;
    }


    
// 循环2次
    for (int count = 0; count < 2++count)
    
{
        
// 等待,直到hEvent事件被激活
        WaitForSingleObject(hEvent, INFINITE);

        cout 
<< "Got The Signal.." << endl;
    }


    
// 关闭事件的句柄
    CloseHandle(hEvent);

    cout 
<< "End The Thread" << endl;

    
return 0;
}


int main()
{
    
// 创建一个自动重置事件("MyEvent"为它的标识):当它被激活后将自动重置为未激活状态
    HANDLE hEvent = CreateEvent(NULL, falsefalse, (LPCWSTR)"MyEvent");
    
if (!hEvent)
    
{
        
return -1;
    }


    
// 创建一个线程,这个线程执行ThreadFun()函数
    DWORD Id;
    HANDLE hThread 
= CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFun, 00&Id);    // LPTHREAD_START_ROUTINE:指向一个函数,该函数通知宿主某个线程已开始执行。(MSDN)
    if (!hThread)
    
{
        CloseHandle(hEvent);
        
return -1;
    }


    
// 在开始前等待1秒。。。。。
    Sleep(1000);

    
// 循环2次(事件被激活2次)
    for (int count = 0; count < 2++count)
    
{
        
// 激活hEvent事件
        SetEvent(hEvent);

        
// 在发送第二次激活状态前等待2秒
        Sleep(2000);
    }


    
// 等待hThread这个线程的结束
    WaitForSingleObject(hThread, INFINITE);

    CloseHandle(hEvent);
    CloseHandle(hThread);

    cout 
<< "" << endl;

    
return 0;
}

// 附加
/****定义全局的
CreateEvent(NULL, false, false, (LPCWSTR)"Global\\MyEvent");
“Global\\xxxEvent ”可以保证:在创建命名时间对象时指定名字是全局的。
这样做的好处如下:
这样创建的内核对象无论出于服务,还是内核中,应用层都可以打开并使用这个内核对象。
CreateEvent( NULL, FALSE, FALSE, "Global\\CSAPP" );  这是一个内核对象。
*/

         说明:上面的代码通过调用“CreateEvent ( NULL , false , false , "MyEvent" ); ”来创建一个事件,他的参数说明如下(网络搜索到的):  
         有四个参数,分别注解
         LPSECURITY_ATTRIBUTES  pEventAttributes :安区参数  一般用户不用考虑它
         BOOL bManualReset:表示SetEvent 置位,WaitForSingleObject使用以此后;信号量的有无,为TRUE 的时候,表示有信号,为FALSE为无信号,也可以理解为SetEvent 的作用是置一次信号,与PulseEvent函数作用相同了。(我的理解:就是是否能过自动重置为未激活状态。false时意味是可以自动重置的,true表示必须手动,即调用ResetEvent)
         BOOL bInitialState:表示初始时的信号量有无,为TRUE 的时,表示有信号,反之无信号
         LPCTSTR lpName:信号量的别名
         其中主要以BOOL bManualReset,BOOL bInitialState的使用最为重要,采用那种配对方式取决于程序的工作方式了。

4、手动重置Win32事件

         需要手动来重置,只要在创建事件时把第二个参数由false改为true即可。这意味着在将事件激活后,如果需要使事件为非激活的状态,必须手动(explicit明确)的调用API(ResetEvent)。下面的代码和上面的很相似,只在main中重置事件为非激活状态时,加入了一些代码:
#include <Windows.h>
#include 
<iostream>

using namespace std;

// 需要激活的线程
DWORD WINAPI ThreadFun(LPVOID n)
{
    cout 
<< "Thread Instantiated" << endl;

    
// 获得激活事件的句柄(以"MyEvent"为标识)
    HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, false, (LPCWSTR)"MyEvent");  //  (LPCWSTR)在vs2010,不加入的话会报错
    if (!hEvent)
    
{
        
return -1;
    }


    
// 循环2次
    for (int count = 0; count < 2++count)
    
{
        
// 等待,直到hEvent事件被激活
        WaitForSingleObject(hEvent, INFINITE);

        cout 
<< "Got The Signal.." << endl;

        
// 使hEvent该事件的状态为非激活状态
        ResetEvent(hEvent);
        cout 
<< "Reset The Event No Signal.." << endl;
    }


    
// 关闭事件的句柄
    CloseHandle(hEvent);

    cout 
<< "End The Thread" << endl;

    
return 0;
}


int main()
{
    
// 创建一个自动重置事件("MyEvent"为它的标识):当它被激活后将自动重置为未激活状态
    HANDLE hEvent = CreateEvent(NULL, falsefalse, (LPCWSTR)"MyEvent");
    
if (!hEvent)
    
{
        
return -1;
    }


    
// 创建一个线程,这个线程执行ThreadFun()函数
    DWORD Id;
    HANDLE hThread 
= CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFun, 00&Id);    // LPTHREAD_START_ROUTINE:指向一个函数,该函数通知宿主某个线程已开始执行。(MSDN)
    if (!hThread)
    
{
        CloseHandle(hEvent);
        
return -1;
    }


    
// 在开始前等待1秒。。。。。
    Sleep(1000);

    
// 循环2次(事件被激活2次)
    for (int count = 0; count < 2++count)
    
{
        
// 激活hEvent事件
        SetEvent(hEvent);

        
// 在发送第二次激活状态前等待2秒
        Sleep(2000);
    }


    
// 等待hThread这个线程的结束
    WaitForSingleObject(hThread, INFINITE);

    CloseHandle(hEvent);
    CloseHandle(hThread);

    cout 
<< "" << endl;

    
return 0;
}

         这篇文件主要讲在多线程中控制线程的激活、等待、退出等处理形式。

         原文地址:http://www.codeproject.com/KB/winsdk/Win32_Event_Handling.aspx 

         源码下载:
         原作者代码:/Files/tiger7/Win32_Event_Handling.zip
         VS2010代码:/Files/tiger7/Thread_Sync.rar

posted on 2011-04-01 22:23 tiger7 阅读(2002) 评论(2)  编辑 收藏 引用 所属分类: VC

评论

# re: 怎样使用WIN32的事件(Event)核心对象----How to use WIN32 Event Kernel Object(源码下载) 2011-07-30 09:39 尚磊冬

能还更详细地说明事件体的调度,也即当很多线程或进程等待一个事件时,内核是如何调度的,一次将所有等待的线程或进程都进行入就绪态,还是一次仅让其中的一个出来。  回复  更多评论   

# re: 怎样使用WIN32的事件(Event)核心对象----How to use WIN32 Event Kernel Object(源码下载) 2011-08-09 08:59 tiger7

@尚磊冬
WaitForMultipleObjects应该是等待多个线程的,具体的情况我还没试过。。。。。你可以网上搜索下,内容很多的  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2011年8月>
31123456
78910111213
14151617181920
21222324252627
28293031123
45678910

导航

统计

公告

welcome to tiger's blog.

常用链接

留言簿

文章分类

文章档案

搜索

最新评论