`
mywebcode
  • 浏览: 997643 次
文章分类
社区版块
存档分类
最新评论

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函数将它设为非触发态。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics