• Chapter09"内核模式下的线程同步"之事件内核对象


           有两种事件内核对象:自动事件和手动事件。当手动事件被触发时,所以该事件的等待线程都编程可调度状态;而自动事件被触发时,只有个一个等待该事件线程变成可调度状态。

           下面再逐个讲解Event的相关函数:

    a)       创建事件函数——CreateEvent函数

               HANDLE CreateEvent(
                                       PSECURITY_ATTRIBUTESpsa,
                                       BOOLbManualReset,
                                       BOOLbInitialState,
                                       PCTSTRpszName);
              具体的函数参数及用法,请查看上面的超链接。

    b)       第二创建事件的函数——CreateEventEx函数
               HANDLE CreateEventEx(
                                       PSECURITY_ATTRIBUTESpsa,
                                       PCTSTRpszName,
                                       DWORDdwFlags,
                                       DWORDdwDesiredAccess);

    c)       访问某个打开的事件(Event)——OpenEvent函数
               HANDLE OpenEvent(
                                       DWORDdwDesiredAccess,
                                       BOOLbInherit,
                                       PCTSTRpszName)
              在pszName传递创建事件时函数的pszName参数值。

    d)       使得某个事件处于触发状态——SetEvent函数
              BOOL SetEvent(HANDLE hEvent);

    e)       将某个事件设置为非触发状态——ResetEvent函数
              BOOL ResetEvent(HANDLE hEvent);

    f)        特别的函数——PluseEvent函数
              BOOL PulseEvent(HANDLE hEvent);
             其作用相当于在调用SetEvent函数后立即调用ResetEvent函数,功能就是一次启用一个线程。因为手动方式的事件时,当事件触发时,所有的该事件阻塞的线程都会转为可调度状态。如果你调用PluseEvent函数后,在系统调用某一个线程后,由于立马将事件设置为非触发状态,这是其他线程也就再次被阻塞了。解释起来好像比较麻烦,不过该函数在实际使用过程中也少有用到。

    看一个创建事件时设置手动方式的事件(manual-reset events)示例:

    // Create a global handle to a manual-reset, nonsignaled event.
    HANDLE g_hEvent;
    int WINAPI _tWinMain(...) {
    // Create the manual-reset, nonsignaled event.
    g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    // Spawn 3 new threads.
    HANDLE hThread[3];
    DWORD dwThreadID;
    hThread[0] = _beginthreadex(NULL, 0, WordCount, NULL, 0, &dwThreadID);
    hThread[1] = _beginthreadex(NULL, 0, SpellCheck, NULL, 0, &dwThreadID);
    hThread[2] = _beginthreadex(NULL, 0, GrammarCheck, NULL, 0, &dwThreadID);
    OpenFileAndReadContentsIntoMemory(...);
    // Allow all 3 threads to access the memory.
    SetEvent(g_hEvent);
    ...
    }
    DWORD WINAPI WordCount(PVOID pvParam) {
    // Wait until the file's data is in memory.
    WaitForSingleObject(g_hEvent, INFINITE);
    // Access the memory block.
    ...
    return(0);
    }
    DWORD WINAPI SpellCheck (PVOID pvParam) {
    // Wait until the file's data is in memory.
    WaitForSingleObject(g_hEvent, INFINITE);
    // Access the memory block.
    ...
    return(0);
    }
    DWORD WINAPI GrammarCheck (PVOID pvParam) {
    // Wait until the file's data is in memory.
    WaitForSingleObject(g_hEvent, INFINITE);
    // Access the memory block.
    ...
    return(0);
    }

    创建事件时设置为自动方式时的事件(auto-reset event)示例:

    // Create a global handle to a auto-reset, nonsignaled event.
    HANDLE g_hEvent;
    int WINAPI _tWinMain(...) {
    // Create the auto-reset, nonsignaled event.
    g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    // Spawn 3 new threads.
    HANDLE hThread[3];
    DWORD dwThreadID;
    hThread[0] = _beginthreadex(NULL, 0, WordCount, NULL, 0, &dwThreadID);
    hThread[1] = _beginthreadex(NULL, 0, SpellCheck, NULL, 0, &dwThreadID);
    hThread[2] = _beginthreadex(NULL, 0, GrammarCheck, NULL, 0, &dwThreadID);
    OpenFileAndReadContentsIntoMemory(...);
    // Allow all 3 threads to access the memory.
    SetEvent(g_hEvent);
    ...
    }
    DWORD WINAPI WordCount(PVOID pvParam) {
    // Wait until the file's data is in memory.
    WaitForSingleObject(g_hEvent, INFINITE);
    // Access the memory block.
    ...
    SetEvent(g_hEvent);
    return(0);
    }
    DWORD WINAPI SpellCheck (PVOID pvParam) {
    // Wait until the file's data is in memory.
    WaitForSingleObject(g_hEvent, INFINITE);
    // Access the memory block.
    ...
    SetEvent(g_hEvent);
    return(0);
    }
    DWORD WINAPI GrammarCheck (PVOID pvParam) {
    // Wait until the file's data is in memory.
    WaitForSingleObject(g_hEvent, INFINITE);
    // Access the memory block.
    ...
    SetEvent(g_hEvent);
    return(0);
    }

          
    分析:

          对比上面的代码示例,细心的话你会发现:在自动方式下的代码中,每个线程在返回前都会调用SetEvent函数将事件设置为触发状态;而手动方式事件对应的函数中没有调用这个函数。
          这是因为在自动方式下,事件每次转化为触发状态时只能使一个线程变成可调度状态,为了让其他线程也能被执行,所以在每个线程返回前再次将事件设置为触发状态,使得其他等待该事件的线程转为可调度状态从而被执行。
          而手动方式下,则不同,当手动方式事件被SetEvent函数触发一次,它就一直保持触发态,直到再次调用ReSetEvent函数将它设为非触发态。

  • 相关阅读:
    php中处理汉字字符串长度:strlen和mb_strlen
    天气应用收获总结
    word文档每章的页眉页脚设置
    python资料汇总
    linux 命令——61 wget(转)
    linux 命令——58 ss(转)
    linux 命令——56 ss(转)
    linux 命令——56 netstat(转)
    linux 命令——55 traceroute(转)
    linux 命令——54 ping(转)
  • 原文地址:https://www.cnblogs.com/java20130722/p/3207198.html
Copyright © 2020-2023  润新知