2011年2月7日 星期一

[ Windows DDP ] 驅動程式的同步處理 : 核心模式下的同步物件 - 互斥體


前言 :
在內核中還有另一個同步物件, 這就是互斥體物件. 前面已經介紹互斥體在應用程式中的使用, 在內核中使用互斥體物件的方法是相似的.

核心模式下的互斥體 :
互斥體在內核中的資料結構是 KMUTEX, 使用前需要初始化互斥體物件, 可以使用 KeInitializeMutex 內核函式, 其宣告如下 :
- Syntax :
  1. VOID KeInitializeMutex(  
  2.   __out  PRKMUTEX Mutex,  
  3.   __in   ULONG Level  
  4. );  

參數說明 :
* 參數 Mutex : 這個參數可以獲得內核互斥體物件的指標.
* 參數 Level : 保留值, 一般設為0.

初始化後的互斥體物件, 就可以使執行緒之間互斥了. 獲得互斥體物件用 KeWaitXX 系列內核函式, 釋放互斥體用 KeReleaseMutex 內核函式.
下面例子展示如何在驅動程式中使用互斥體物件, 首先這個例子新建兩個執行緒, 為了保證執行緒之間不並行執行, 執行緒間使用互斥體進行同步 :
- Driver.cpp : 示範在核心模式下使用 Mutex
  1. VOID MyMutexFun2(IN PVOID pContext)  
  2. {  
  3.     PKMUTEX pkMutex = (PKMUTEX) pContext;  
  4.     // 獲得互斥體  
  5.     KeWaitForSingleObject(pkMutex, Executive, KernelMode, FALSE, NULL);  
  6.     KdPrint(("Enter MyMutexFun2\n"));  
  7.     // 強迫停止 50ms, 模擬執行一段程式碼.  
  8.     KdPrint(("\tExecution...\n"));  
  9.     KeStallExecutionProcessor(2000);  
  10.     KdPrint(("Leave MyMutexFun2\n"));  
  11.     // 釋放互斥體  
  12.     KeReleaseMutex(pkMutex, FALSE);  
  13.     PsTerminateSystemThread(STATUS_SUCCESS);  
  14. }  
  15.   
  16. VOID MyMutexFun1(IN PVOID pContext)  
  17. {  
  18.     PKMUTEX pkMutex = (PKMUTEX) pContext;  
  19.     // 獲得互斥體  
  20.     KeWaitForSingleObject(pkMutex, Executive, KernelMode, FALSE, NULL);  
  21.     KdPrint(("Enter MyMutexFun1\n"));  
  22.     // 強迫停止 50ms, 模擬執行一段程式碼.  
  23.     KdPrint(("\tExecution...\n"));  
  24.     KeStallExecutionProcessor(2000);  
  25.     KdPrint(("Leave MyMutexFun1\n"));  
  26.     // 釋放互斥體  
  27.     KeReleaseMutex(pkMutex, FALSE);  
  28.     PsTerminateSystemThread(STATUS_SUCCESS);  
  29. }  
  30.   
  31. #pragma INITCODE  
  32. VOID TestMutex()  
  33. {  
  34.     HANDLE hMyThread1, hMyThread2;  
  35.     KMUTEX kMutex;  
  36.     // 初始化互斥體  
  37.     KeInitializeMutex(&kMutex, 0);  
  38.     // 新建系統執行緒, 該執行緒是 System 處理程序的執行緒  
  39.     PsCreateSystemThread(&hMyThread1, 0, NULL, NtCurrentProcess(), NULL, MyMutexFun1, &kMutex);  
  40.     PsCreateSystemThread(&hMyThread2, 0, NULL, NtCurrentProcess(), NULL, MyMutexFun2, &kMutex);  
  41.     PVOID Pointer_Array[2];  
  42.     ObReferenceObjectByHandle(hMyThread1, 0, NULL, KernelMode, &Pointer_Array[0], NULL);  
  43.     ObReferenceObjectByHandle(hMyThread2, 0, NULL, KernelMode, &Pointer_Array[1], NULL);  
  44.   
  45.     // 等待多個事件  
  46.     KeWaitForMultipleObjects(2, Pointer_Array, WaitAll, Executive, KernelMode, FALSE, NULL, NULL);  
  47.     ObDereferenceObject(Pointer_Array[0]);  
  48.     ObDereferenceObject(Pointer_Array[1]);  
  49.     KdPrint(("After KeWaitForMultipleObjects\n"));  
  50. }  

底下是執行結果, 查看驅動程式輸出 log 資訊, 可以看出兩個執行緒是以序列方式執行, 這意味著成功地進行同步 :


快速互斥體 :
快速互斥體 (Fast Mutex) 是 DDK 提供的另一種內核同步物件. 它的特性類似前面介紹的普通互斥體物件. 快速互斥體和普通互斥體起到作用完全一樣, 之所以被稱為快速互斥體, 是因為執行速度比普通互斥體快 (這裡指的是獲取與釋放的速度). 然而快速互斥體比普通互斥體多了一個缺點, 就是不能遞迴的獲取互斥體物件. 遞迴的獲取指的是已經獲得互斥體的執行緒, 可以再次獲得這個互斥體. 換句話說互斥體只是互斥其他執行緒, 而不互斥自己所在的的執行緒, 但是快速互斥體則不允許遞迴的情況.
普通互斥體在內核中是用 MUTEX 資料結構描述的, 而快速互斥體在內核中是用 FAST_MUTEX 資料結構描述的. 除此之外對快速互斥體的初始化, 獲取和釋放對應的內核函式也和普通互斥體不同. 初始化快速互斥體的內核函式是 ExInitializeFastMutex, 獲取快速互斥體的內核函式是 ExAcquireFastMutex, 釋放快速互斥體的函式是 ExReleaseFastMutex. 下面例子展示了如何在驅動程式中使用快速互斥體 :
- Driver.cpp : 示範在核心模式下使用 FAST_MUTEX
  1. VOID MyFastMutexFun2(IN PVOID pContext)  
  2. {  
  3.     PFAST_MUTEX pkMutex = (PFAST_MUTEX) pContext;  
  4.     // 獲得互斥體  
  5.     ExAcquireFastMutex(pkMutex);  
  6.     KdPrint(("Enter MyFastMutexFun2\n"));  
  7.     // 強迫停止 50ms, 模擬執行一段程式碼.  
  8.     KdPrint(("\tExecution...\n"));  
  9.     KeStallExecutionProcessor(2000);  
  10.     KdPrint(("Leave MyFastMutexFun2\n"));  
  11.     // 釋放快速互斥體  
  12.     ExReleaseFastMutex(pkMutex);  
  13.     PsTerminateSystemThread(STATUS_SUCCESS);  
  14. }  
  15.   
  16. VOID MyFastMutexFun1(IN PVOID pContext)  
  17. {  
  18.     PFAST_MUTEX pkMutex = (PFAST_MUTEX) pContext;  
  19.     // 獲得互斥體  
  20.     ExAcquireFastMutex(pkMutex);  
  21.     KdPrint(("Enter MyFastMutexFun1\n"));  
  22.     // 強迫停止 50ms, 模擬執行一段程式碼.  
  23.     KdPrint(("\tExecution...\n"));  
  24.     KeStallExecutionProcessor(2000);  
  25.     KdPrint(("Leave MyFastMutexFun1\n"));  
  26.     // 釋放快速互斥體  
  27.     ExReleaseFastMutex(pkMutex);  
  28.     PsTerminateSystemThread(STATUS_SUCCESS);  
  29. }  
  30.   
  31. #pragma INITCODE  
  32. VOID TestFastMutex()  
  33. {  
  34.     HANDLE hMyThread1, hMyThread2;  
  35.     FAST_MUTEX fastMutex;  
  36.     // 初始化快速互斥體  
  37.     ExInitializeFastMutex(&fastMutex);  
  38.     // 新建系統執行緒, 該執行緒是 System 處理程序的執行緒  
  39.     PsCreateSystemThread(&hMyThread1, 0, NULL, NtCurrentProcess(), NULL, MyFastMutexFun1, &fastMutex);  
  40.     PsCreateSystemThread(&hMyThread2, 0, NULL, NtCurrentProcess(), NULL, MyFastMutexFun2, &fastMutex);  
  41.     PVOID Pointer_Array[2];  
  42.     ObReferenceObjectByHandle(hMyThread1, 0, NULL, KernelMode, &Pointer_Array[0], NULL);  
  43.     ObReferenceObjectByHandle(hMyThread2, 0, NULL, KernelMode, &Pointer_Array[1], NULL);  
  44.   
  45.     // 等待多個事件  
  46.     KeWaitForMultipleObjects(2, Pointer_Array, WaitAll, Executive, KernelMode, FALSE, NULL, NULL);  
  47.     ObDereferenceObject(Pointer_Array[0]);  
  48.     ObDereferenceObject(Pointer_Array[1]);  
  49.     KdPrint(("After KeWaitForMultipleObjects\n"));  
  50. }  
This message was edited 3 times. Last update was at 10/01/2011 11:08:57

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...