看流星社区

 找回密码
 注册账号
查看: 2140|回复: 0

多线程 以及多线程安全

[复制链接]

该用户从未签到

发表于 2017-6-1 13:34:17 | 显示全部楼层 |阅读模式
线程的运行级别(IRQL)


中断是指在CPU接到这个请求后停止手上的工作来处理我们的工作(指当出现需要时,CPU暂时停止当前程序的执行转而执行处理新情况的程序和执行过程)
中断优先级是指为使系统能及时响应并处理发生的所有中断,系统根据引起中断事件的重要性和紧迫程度,硬件将中断源分为若干个级别,称作中断优先级。


引用来自8649279
------------------------------------------------------------------------------------------------------------
IRQL级别越高,可调用的API函数就越少。
从高级别开始:




DIRQ,设备级中断,这是硬件设备的中断,只有底层的驱动程序才处理这个中断。


DISPATCH——LEVEL(DL),运行于这个级别的处理器会屏蔽除DPC以外的中断,不能访问可交换内存,所以这个级别能调用的API函数大大减少。




APC——LEVEL(AL),异步调用就运行在这个级别,这是会屏蔽APC级别的中断。在这个级别仍可访问可交换内存。当一个APC中断发生时,处理器提升到APC级别,这是,就禁止了其他的APC中断。驱动程序自己提身高APC级别,以便处理同步操作。


PASSIVE_LEVEL(PL)是最低级的IRQL,不会屏蔽任何中断。用户态应用程序的线程就运行在这个级别上,可以使用可交换的内存。
-----------------------------------------------------------------------------------------------------------------


中断级别要求
1.明白驱动中各个函数的中断级别
2.明白要调用的API的运行级别 RtlCopyUnicodeString
3.PASSIVE级别可以使用任何函数和内存
4.DISPATCH级别只能访问能运行在DISPATCH级别的API和非分页内存
5.NONPAGEPOOL内存可在任何级别使用
6.PAGEDPOOL只能在PASSIVE_LEVEL和APC_LEVEL使用
7.在PASSIVE和APC级别代码中加:PAGED_CODE()宏
  1. #define PAGED_CODE() \
  2.     { if (KeGetCurrentIrql() > APC_LEVEL) { \
  3.           KdPrint(( "EX: Pageable code called at IRQL %d\n", KeGetCurrentIrql() )); \
  4.           ASSERT(FALSE); \
  5.        } \
  6.     }
复制代码
一般的
DriverEntry,DriverUnload  Passive级
各种分发函数  Passive级
完成函数  DL级
各种NDIS回调函数     DL级




内核多线程创建演示
  1. VOID DoFind(IN PVOID pContext)
  2. {
  3. }
  4. void StartThread()
  5. {
  6.           HANDLE hThread         = NULL;
  7.           PVOID objtowait        = 0;
  8.           NTSTATUS dwStatus =
  9.         PsCreateSystemThread(
  10.         &hThread,
  11.         0,
  12.         NULL,
  13.         (HANDLE)0,
  14.         NULL,
  15.         DoFind,
  16.         NULL
  17.         );
  18.         if (!NT_SUCCESS(dwStatus)
  19.          {
  20.                              return;
  21.         }
  22.         if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
  23.          {
  24.                 dwStatus=KfRaiseIrql(PASSIVE_LEVEL);
  25.         }
  26.         if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
  27.          {
  28.                 return;
  29.         }       
  30.         ObReferenceObjectByHandle(
  31.                 hThread,
  32.                 THREAD_ALL_ACCESS,
  33.                 NULL,
  34.                 KernelMode,
  35.                 &objtowait,
  36.                 NULL
  37.                 );
  38.         KeWaitForSingleObject(objtowait,Executive,KernelMode,FALSE,NULL);
  39.         <span style="font-family: 'Courier New'; line-height: 18px; white-space: pre-wrap;">ObDereferenceObject</span>(objtowait);
  40.         return;
  41. }
复制代码

同步互斥
互斥(A和B只能一个访问)
KSPIN_LOCK
ERESOURCE
FAST_MUTEX
同步(A告诉B发生了什么事)
KEVENT
KSEMAPHORE
KMUTEX
KeWaitForSingleObject
KEVENT
KMUTEX/KMUTANT
KPROCESS
KQUEUE
KSEMAPHORE
KTHREAD
KTIMER(都带dispatcher header)
fileobject/driverobject等不行


KeWaitForSingleObject演示:
  1. LARGE_INTEGER TimeOut =  {0};
  2. TimeOut.QuadPart = -10 * 10000000i64;//10s
  3. KeWaitForSingleObject(         &kSemaphore,
  4.         Executive,
  5.         KernelMode,
  6.         FALSE,
  7.         &TimeOut//0,不等;NULL,无限等待
  8.         );
复制代码
同步:
一.KEVENT
用于线程同步
Event两个状态:
Signaled
Non-signaled
Event两个类别:
Notification事件:不自动恢复
synchronization事件:自动恢复


创建:IoCreateNotificationEvent //创建一个有名字的事件 供其它进程 或R3 R0通信
  1. KEVENT waitEvent;
  2. KeInitializeEvent(&waitEvent,
  3.                NotificationEvent,
  4.                FALSE );
  5. //开灯
  6. KeSetEvent(&waitEvent,
  7.         IO_NO_INCREMENT,
  8.         FALSE );
  9. //等灯
  10. KeWaitForSingleObject(
  11.                     &waitEvent,
  12.                     Executive,
  13.                     KernelMode,
  14.                     FALSE,
  15.                     NULL );//0,立即返回;
  16.                                 //NULL无限等待
  17. //关灯
  18. KeClearEvent(&waitEvent);
  19. KeResetEvent(&waitEvent);
复制代码

例子:进程创建监视:R0到R3同步通信 这个例子在xp和win7中的效果是不同的,xp上只要得到了信号就会退出,win7不会 原因:
-------------------------------------------------------------------------------------------------------
在XP中创建一个进程就退出 原因是WaitForSingleObject 等待成功后返回0
而在win7中 WaitForSingleObject 等待成功后返回0xffffffff;

------------------------------------------------------------------------------------------------------
Event创建:
  1. L\\BaseNamedObjects\\ProcEvent
  2. IoCreateNotificationEvent
复制代码
数据存放:使用设备扩展 详细使用方法见下面完整代码
定义
typedef struct _DEVICE_EXTENSION
{
  HANDLE       hProcessHandle;    // 事件对象句柄
  PKEVENT      ProcessEvent;      // 用户和内核通信的事件对象指针
  HANDLE       hParentId;          // 在回调函数中保存进程信息
  HANDLE       hProcessId;
  BOOLEAN     bCreate;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
IoCreateDevice( DriverObject, sizeof(DEVICE_EXTENSION), &ustrDeviceName,...);
访问:
// 获得DEVICE_EXTENSION结构
PDEVICE_EXTENSION deviceExtension =
(PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;
// 保存信息
deviceExtension->hParentId = hParentId;
deviceExtension->hProcessId = PId;
deviceExtension->bCreate = bCreate;
事件触发
// 触发事件,通知应用程序
KeSetEvent(deviceExtension-&gtrocessEvent, 0, FALSE);
KeClearEvent(deviceExtension-&gtrocessEvent);


R3
#define EVENT_NAME  L"\\Global\\ProcEvent"


// 打开内核事件对象
HANDLE hProcessEvent = ::OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);


while (::WaitForSingleObject(hProcessEvent, INFINITE))
{
//bugs to fix here
//发送DeviceIoControl下去拿数据
}


当然是做监控 最好不要采用这种方式,原因是有个死循环 虽然通过sleep可以减低cpu占用率 但这个思路还是错的 只为实验而已
R3:
  1. // ProcWatchClientConsole.cpp : Defines the entry point for the console application.
  2. //
  3. //#include "stdafx.h"
  4. #include "windows.h"
  5. #include "winioctl.h"
  6. #include "stdio.h"
  7. BOOL LoadDriver(char* lpszDriverName,char* lpszDriverPath);
  8. BOOL UnloadDriver(char * szSvrName);
  9. #define EVENT_NAME    L"ProcEvent"
  10. #define DRIVER_NAME          "ProcWatch"
  11. #define DRIVER_PATH          ".\\ProcWatch.sys"
  12. #pragma comment(lib,"Advapi32.lib")
  13. #define                CTRLCODE_BASE 0x8000
  14. #define                MYCTRL_CODE(i) \
  15. CTL_CODE(FILE_DEVICE_UNKNOWN,CTRLCODE_BASE + i, METHOD_BUFFERED, FILE_ANY_ACCESS)
  16. #define                IOCTL_PROCWATCH                MYCTRL_CODE(0)
  17. typedef struct _ProcMonData
  18. {
  19.     HANDLE  hParentId;
  20.     HANDLE  hProcessId;
  21.     BOOLEAN bCreate;
  22. }ProcMonData, *PProcMonData;
  23. int main(int argc, char* argv[])
  24. {
  25.         ProcMonData pmdInfoNow = {0};
  26.         ProcMonData pmdInfoBefore = {0};
  27.         if (!LoadDriver(DRIVER_NAME, DRIVER_PATH))
  28.         {
  29.                 printf("LoadDriver Failed:%x\n", GetLastError());
  30.                 return -1;
  31.         }
  32.     // 打开驱动设备对象
  33.     HANDLE hDriver = ::CreateFile(
  34.                 "\\\\.\\ProcWatch",
  35.                 GENERIC_READ | GENERIC_WRITE,
  36.                 0,
  37.                 NULL,
  38.                 OPEN_EXISTING,
  39.                 FILE_ATTRIBUTE_NORMAL,
  40.                 NULL);
  41.     if (hDriver == INVALID_HANDLE_VALUE)
  42.     {
  43.         printf("Open device failed:%x\n", GetLastError());
  44.                 UnloadDriver(DRIVER_NAME);
  45.         return -1;
  46.     }
  47.     // 打开内核事件对象
  48.     HANDLE hProcessEvent = ::OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);
  49.     //while (TRUE)
  50.     //{
  51.         //DWORD    dwRet        = 0;
  52.         //BOOL     bRet        = FALSE;
  53.         //::WaitForSingleObject(hProcessEvent, INFINITE);
  54.         //WAIT_OBJECT_0
  55.                 //WAIT_TIMEOUT
  56.     while (1)
  57.     {
  58.                 ULONG test = ::WaitForSingleObject(hProcessEvent, INFINITE);
  59.                 Sleep(100);
  60.         DWORD    dwRet        = 0;
  61.         BOOL     bRet        = FALSE;
  62.         bRet = ::DeviceIoControl(
  63.                         hDriver,
  64.                         IOCTL_PROCWATCH,
  65.                         NULL,
  66.                         0,
  67.                         &pmdInfoNow,
  68.                         sizeof(pmdInfoNow),
  69.                         &dwRet,
  70.                         NULL);
  71.         if (bRet)
  72.         {
  73.             if (pmdInfoNow.hParentId != pmdInfoBefore.hParentId || \
  74.                 pmdInfoNow.hProcessId != pmdInfoBefore.hProcessId || \
  75.                 pmdInfoNow.bCreate != pmdInfoBefore.bCreate)
  76.             {
  77.                 if (pmdInfoNow.bCreate)
  78.                 {
  79.                     printf("ProcCreated,PID = %d\n", pmdInfoNow.hProcessId);
  80.                 }
  81.                 else
  82.                 {
  83.                     printf("ProcTeminated,PID = %d\n", pmdInfoNow.hProcessId);
  84.                 }
  85.                 pmdInfoBefore = pmdInfoNow;
  86.             }
  87.         }
  88.         else
  89.         {
  90.             printf("Get Proc Info Failed!\n");
  91.             break;
  92.         }
  93.     }
  94.     ::CloseHandle(hDriver);
  95.         UnloadDriver(DRIVER_NAME);
  96.     return 0;
  97. }
  98. //装载NT驱动程序
  99. BOOL LoadDriver(char* lpszDriverName,char* lpszDriverPath)
  100. {
  101.         char szDriverImagePath[256] = {0};
  102.         //得到完整的驱动路径
  103.         GetFullPathName(lpszDriverPath, 256, szDriverImagePath, NULL);
  104.         BOOL bRet = FALSE;
  105.         SC_HANDLE hServiceMgr=NULL;//SCM管理器的句柄
  106.         SC_HANDLE hServiceDDK=NULL;//NT驱动程序的服务句柄
  107.         //打开服务控制管理器
  108.         hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
  109.         if( hServiceMgr == NULL )  
  110.         {
  111.                 //OpenSCManager失败
  112.                 printf( "OpenSCManager() Faild %d ! \n", GetLastError() );
  113.                 bRet = FALSE;
  114.                 goto BeforeLeave;
  115.         }
  116.         else
  117.         {
  118.                 ////OpenSCManager成功
  119.                 printf( "OpenSCManager() ok ! \n" );  
  120.         }
  121.         //创建驱动所对应的服务
  122.         hServiceDDK = CreateService( hServiceMgr,
  123.                 lpszDriverName, //驱动程序的在注册表中的名字  
  124.                 lpszDriverName, // 注册表驱动程序的 DisplayName 值  
  125.                 SERVICE_ALL_ACCESS, // 加载驱动程序的访问权限  
  126.                 SERVICE_KERNEL_DRIVER,// 表示加载的服务是驱动程序  
  127.                 SERVICE_DEMAND_START, // 注册表驱动程序的 Start 值  
  128.                 SERVICE_ERROR_IGNORE, // 注册表驱动程序的 ErrorControl 值  
  129.                 szDriverImagePath, // 注册表驱动程序的 ImagePath 值  
  130.                 NULL,  //GroupOrder HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GroupOrderList
  131.                 NULL,  
  132.                 NULL,  
  133.                 NULL,  
  134.                 NULL);  
  135.         DWORD dwRtn;
  136.         //判断服务是否失败
  137.         if( hServiceDDK == NULL )  
  138.         {  
  139.                 dwRtn = GetLastError();
  140.                 if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_EXISTS )  
  141.                 {  
  142.                         //由于其他原因创建服务失败
  143.                         printf( "CrateService() Faild %d ! \n", dwRtn );  
  144.                         bRet = FALSE;
  145.                         goto BeforeLeave;
  146.                 }  
  147.                 else  
  148.                 {
  149.                         //服务创建失败,是由于服务已经创立过
  150.                         printf( "CrateService() Faild Service is ERROR_IO_PENDING or ERROR_SERVICE_EXISTS! \n" );  
  151.                 }
  152.                 // 驱动程序已经加载,只需要打开  
  153.                 hServiceDDK = OpenService( hServiceMgr, lpszDriverName, SERVICE_ALL_ACCESS );  
  154.                 if( hServiceDDK == NULL )  
  155.                 {
  156.                         //如果打开服务也失败,则意味错误
  157.                         dwRtn = GetLastError();  
  158.                         printf( "OpenService() Faild %d ! \n", dwRtn );  
  159.                         bRet = FALSE;
  160.                         goto BeforeLeave;
  161.                 }  
  162.                 else
  163.                 {
  164.                         printf( "OpenService() ok ! \n" );
  165.                 }
  166.         }  
  167.         else  
  168.         {
  169.                 printf( "CrateService() ok ! \n" );
  170.         }
  171.         //开启此项服务
  172.         bRet= StartService( hServiceDDK, NULL, NULL );  
  173.         if( !bRet )  
  174.         {  
  175.                 DWORD dwRtn = GetLastError();  
  176.                 if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_ALREADY_RUNNING )  
  177.                 {  
  178.                         printf( "StartService() Faild %d ! \n", dwRtn );  
  179.                         bRet = FALSE;
  180.                         goto BeforeLeave;
  181.                 }  
  182.                 else  
  183.                 {  
  184.                         if( dwRtn == ERROR_IO_PENDING )  
  185.                         {  
  186.                                 //设备被挂住
  187.                                 printf( "StartService() Faild ERROR_IO_PENDING ! \n");
  188.                                 bRet = FALSE;
  189.                                 goto BeforeLeave;
  190.                         }  
  191.                         else  
  192.                         {  
  193.                                 //服务已经开启
  194.                                 printf( "StartService() Faild ERROR_SERVICE_ALREADY_RUNNING ! \n");
  195.                                 bRet = TRUE;
  196.                                 goto BeforeLeave;
  197.                         }  
  198.                 }  
  199.         }
  200.         bRet = TRUE;
  201. //离开前关闭句柄
  202. BeforeLeave:
  203.         getchar();
  204.         if(hServiceDDK)
  205.         {
  206.                 CloseServiceHandle(hServiceDDK);
  207.         }
  208.         if(hServiceMgr)
  209.         {
  210.                 CloseServiceHandle(hServiceMgr);
  211.         }
  212.         return bRet;
  213. }
  214. //卸载驱动程序  
  215. BOOL UnloadDriver( char * szSvrName )  
  216. {
  217.         BOOL bRet = FALSE;
  218.         SC_HANDLE hServiceMgr=NULL;//SCM管理器的句柄
  219.         SC_HANDLE hServiceDDK=NULL;//NT驱动程序的服务句柄
  220.         SERVICE_STATUS SvrSta;
  221.         //打开SCM管理器
  222.         hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );  
  223.         if( hServiceMgr == NULL )  
  224.         {
  225.                 //带开SCM管理器失败
  226.                 printf( "OpenSCManager() Faild %d ! \n", GetLastError() );  
  227.                 bRet = FALSE;
  228.                 goto BeforeLeave;
  229.         }  
  230.         else  
  231.         {
  232.                 //带开SCM管理器失败成功
  233.                 printf( "OpenSCManager() ok ! \n" );  
  234.         }
  235.         //打开驱动所对应的服务
  236.         hServiceDDK = OpenService( hServiceMgr, szSvrName, SERVICE_ALL_ACCESS );  
  237.         if( hServiceDDK == NULL )  
  238.         {
  239.                 //打开驱动所对应的服务失败
  240.                 printf( "OpenService() Faild %d ! \n", GetLastError() );  
  241.                 bRet = FALSE;
  242.                 goto BeforeLeave;
  243.         }  
  244.         else  
  245.         {  
  246.                 printf( "OpenService() ok ! \n" );  
  247.         }  
  248.         //停止驱动程序,如果停止失败,只有重新启动才能,再动态加载。  
  249.         if( !ControlService( hServiceDDK, SERVICE_CONTROL_STOP , &SvrSta ) )  
  250.         {  
  251.                 printf( "ControlService() Faild %d !\n", GetLastError() );  
  252.         }  
  253.         else  
  254.         {
  255.                 //打开驱动所对应的失败
  256.                 printf( "ControlService() ok !\n" );  
  257.         }  
  258.         //动态卸载驱动程序。  
  259.         if( !DeleteService( hServiceDDK ) )  
  260.         {
  261.                 //卸载失败
  262.                 printf( "DeleteSrevice() Faild %d !\n", GetLastError() );  
  263.         }  
  264.         else  
  265.         {  
  266.                 //卸载成功
  267.                 printf( "DelServer:deleteSrevice() ok !\n" );  
  268.         }  
  269.         bRet = TRUE;
  270. BeforeLeave:
  271. //离开前关闭打开的句柄
  272.         if(hServiceDDK)
  273.         {
  274.                 CloseServiceHandle(hServiceDDK);
  275.         }
  276.         if(hServiceMgr)
  277.         {
  278.                 CloseServiceHandle(hServiceMgr);
  279.         }
  280.         return bRet;       
  281. }
复制代码
R0:

  1. #include "ntddk.h"
  2. #include "windef.h"
  3. #define EVENT_NAME    L"\\BaseNamedObjects\\ProcEvent"
  4. #define DEVICE_NAME          L"\\Device\\ProcWatch"
  5. #define LINK_NAME          L"\\DosDevices\\ProcWatch"
  6. #define                CTRLCODE_BASE 0x8000
  7. #define                MYCTRL_CODE(i) \
  8.         CTL_CODE(FILE_DEVICE_UNKNOWN,CTRLCODE_BASE + i, METHOD_BUFFERED, FILE_ANY_ACCESS)
  9. #define                IOCTL_PROCWATCH                MYCTRL_CODE(0)
  10. typedef struct _ProcMonData
  11. {
  12.     HANDLE  hParentId;
  13.     HANDLE  hProcessId;
  14.     BOOLEAN bCreate;
  15. }ProcMonData, *PProcMonData;
  16. VOID DriverUnload(IN PDRIVER_OBJECT DriverObject);
  17. NTSTATUS CommonDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
  18. NTSTATUS IoctrlDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
  19. VOID ProcessCreateMon( IN HANDLE hParentId, IN HANDLE PId, IN BOOLEAN bCreate);
  20. typedef struct _DEVICE_EXTENSION
  21. {
  22.     HANDLE             hProcessHandle;        // 事件对象句柄
  23.     PKEVENT            ProcessEvent;          // 用户和内核通信的事件对象指针
  24.     HANDLE             hParentId;             // 在回调函数中保存进程信息
  25.     HANDLE             hProcessId;
  26.     BOOLEAN            bCreate;
  27. } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
  28. PDEVICE_OBJECT g_pDeviceObject = NULL;
  29. // 驱动入口
  30. NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
  31. {
  32.         UNICODE_STRING        ustrDeviceName = {0};
  33.         UNICODE_STRING        ustrLinkName = {0};
  34.         PDEVICE_OBJECT        deviceObject = NULL;
  35.         NTSTATUS                status = STATUS_SUCCESS;
  36.         int                                i = 0;
  37.         UNICODE_STRING        ustrEventStr = {0};       
  38.         PDEVICE_EXTENSION pDeviceExtension = NULL;
  39.         //建立设备
  40.         RtlInitUnicodeString( &ustrDeviceName, DEVICE_NAME );
  41.         status = IoCreateDevice( DriverObject,
  42.           sizeof(DEVICE_EXTENSION),
  43.           &ustrDeviceName,
  44.           FILE_DEVICE_UNKNOWN,
  45.           0,
  46.           FALSE,
  47.           &deviceObject
  48.           );
  49.        
  50.         if (!NT_SUCCESS( status ))
  51.         {
  52.                 return status;
  53.         }
  54.         deviceObject->Flags |= DO_BUFFERED_IO;
  55.         g_pDeviceObject = deviceObject;
  56.         // 创建事件对象与应用层通信
  57.         RtlInitUnicodeString(&ustrEventStr, EVENT_NAME);
  58.         pDeviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
  59.    
  60.         pDeviceExtension->ProcessEvent =
  61.                 IoCreateNotificationEvent(&ustrEventStr,
  62.                 &pDeviceExtension->hProcessHandle);
  63.         KeClearEvent(pDeviceExtension->ProcessEvent);            // 设置为非受信状态
  64.         RtlInitUnicodeString( &ustrLinkName, LINK_NAME);
  65.         status = IoCreateSymbolicLink(&ustrLinkName, &ustrDeviceName);
  66.         if (!NT_SUCCESS( status ))
  67.         {
  68.                 IoDeleteDevice(DriverObject->DeviceObject);
  69.                 return status;
  70.         }
  71.         status = PsSetCreateProcessNotifyRoutine(ProcessCreateMon, FALSE);
  72.         if (!NT_SUCCESS( status ))
  73.         {
  74.                   IoDeleteDevice(DriverObject->DeviceObject);
  75.                   DbgPrint("PsSetCreateProcessNotifyRoutine()\n");
  76.                   return status;
  77.         }  
  78.         for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)  
  79.         {
  80.                   DriverObject->MajorFunction[i] = CommonDispatch;
  81.         }
  82.         DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoctrlDispatch;
  83.         DriverObject->DriverUnload = DriverUnload;
  84.         return STATUS_SUCCESS;
  85. }
  86. VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
  87. {
  88.         UNICODE_STRING ustrLinkName;
  89.         PsSetCreateProcessNotifyRoutine(ProcessCreateMon, TRUE);
  90.         RtlInitUnicodeString(&ustrLinkName, LINK_NAME);
  91.         IoDeleteSymbolicLink(&ustrLinkName);
  92.         IoDeleteDevice(DriverObject->DeviceObject);
  93. }
  94. //处理设备对象操作
  95. NTSTATUS CommonDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  96. {
  97.         Irp->IoStatus.Status = STATUS_SUCCESS;
  98.         Irp->IoStatus.Information = 0L;
  99.         IoCompleteRequest( Irp, 0 );
  100.         return Irp->IoStatus.Status;
  101. }
  102. NTSTATUS IoctrlDispatch(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
  103. {
  104.         NTSTATUS                        ntStatus = STATUS_SUCCESS;
  105.         PVOID                                pUserBuffer = NULL;
  106.         ULONG                                ulInputSize = 0;
  107.         ULONG                                ulOutputSize = 0;
  108.         PIO_STACK_LOCATION        pIrpStack = NULL;
  109.         ULONG                                ulIoCtrlCode = 0;
  110.         PProcMonData                pProcMonData = NULL;
  111.         PDEVICE_EXTENSION        pDeviceExtension  = NULL;
  112.         pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  113.         pUserBuffer = pIrp->AssociatedIrp.SystemBuffer;
  114.         pProcMonData = (PProcMonData)pUserBuffer;
  115.         ulIoCtrlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
  116.         ulInputSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
  117.         ulOutputSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  118.         switch(ulIoCtrlCode)
  119.         {
  120.         case IOCTL_PROCWATCH:
  121.                 pDeviceExtension = (PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;
  122.                 pProcMonData->bCreate = pDeviceExtension->bCreate;
  123.                 pProcMonData->hParentId = pDeviceExtension->hParentId;
  124.                 pProcMonData->hProcessId = pDeviceExtension->hProcessId;
  125.                 break;
  126.         default:
  127.                 ntStatus = STATUS_INVALID_PARAMETER;
  128.                 ulOutputSize = 0;
  129.                 break;
  130.         }
  131.         pIrp->IoStatus.Status = ntStatus;
  132.         pIrp->IoStatus.Information = ulOutputSize;
  133.         IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  134.         return ntStatus;
  135. }
  136. VOID ProcessCreateMon ( IN HANDLE hParentId, IN HANDLE PId,IN BOOLEAN bCreate )
  137. {
  138.     // 获得DEVICE_EXTENSION结构
  139.     PDEVICE_EXTENSION deviceExtension =
  140.                 (PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;
  141.     // 保存信息
  142.     deviceExtension->hParentId = hParentId;
  143.     deviceExtension->hProcessId = PId;
  144.     deviceExtension->bCreate = bCreate;
  145.     // 触发事件,通知应用程序
  146.     KeSetEvent(deviceExtension->ProcessEvent, 0, FALSE);
  147.     KeClearEvent(deviceExtension->ProcessEvent);
  148. }
复制代码

注意了 上面这个工程中有个循环 ,循环中有个变量时test 这个变量在xp下 一般返回0 在win7 下返回0xffffffff;
这个代码没有改之前是
  1. while (::WaitForSingleObject(hProcessEvent, INFINITE))
  2. {
  3.                 ....
  4. }
复制代码
这会影响循环是否keep runing



2.KSEMAPHORE
比如工作者与消费者之间 工作者增加一个资源 消费者才能买一个 消费者买了一个 就减少一个资源
用于同步与多个资源共享访问
  1. KSEMAPHORE kSemaphore;
  2. KeInitializeSemaphore(
  3.     &kSemaphore,
  4.     1,//信号量的初始值
  5.     2 //信号量的最大值
  6.     );
  7. LARGE_INTEGER waitTime = {0};
  8. waitTime.QuadPart = -1*10000000i64;
  9. KeWaitForSingleObject(&kSemaphore, Executive, KernelMode, FALSE, &waitTime);//0,立即返回;NULL,无限等待
  10. KeReleaseSemaphore(&kSemaphore ,IO_NO_INCREMENT , 1 , FALSE );
复制代码

例子:工作者 与 消费者
  1. #include <ntddk.h>
  2. ULONG        g_ulTotal = 0;
  3. KSEMAPHORE g_kSemaphore;
  4. VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
  5. {
  6.         DbgPrint("Goodbye, driver\n");
  7. }
  8. VOID Worker(IN PVOID pContext)
  9. {
  10.         ULONG i = 0;
  11.         LARGE_INTEGER waitTime = {0};
  12.         waitTime.QuadPart = -3*10000000i64;
  13.         while(i < 10)
  14.         {
  15.                 g_ulTotal++;
  16.                 KeReleaseSemaphore(&g_kSemaphore ,IO_NO_INCREMENT , 1 , FALSE );//增加一个资源semaphore
  17.                 DbgPrint("Worker:produced 1, total:%x\n", g_ulTotal);
  18.                 i++;
  19.                 KeDelayExecutionThread(KernelMode, FALSE, &waitTime);//延迟3秒
  20.         }
  21. }
  22. VOID Consumer(IN PVOID pContext)
  23. {
  24.         ULONG i = 10;
  25.         LARGE_INTEGER waitTime = {0};
  26.         waitTime.QuadPart = -3*10000000i64;
  27.         while(i > 0)
  28.         {
  29.                
  30.                 KeWaitForSingleObject(&g_kSemaphore, Executive, KernelMode, FALSE, NULL);//等待资源并减少一个semaphore(等待成功后减少一个)
  31.                 g_ulTotal--;
  32.                 DbgPrint("Consumer:consumed 1, total:%x\n", g_ulTotal);
  33.                 i--;
  34.                 KeDelayExecutionThread(KernelMode, FALSE, &waitTime);//延迟3秒
  35.         }
  36. }
  37. void StartThreads()
  38. {
  39.         HANDLE hThread1          = NULL;
  40.         HANDLE hThread2          = NULL;
  41.         PVOID  objtowait[2] = {NULL};
  42.         NTSTATUS ntStatus =
  43.                 PsCreateSystemThread(//创建工作者线程
  44.                 &hThread1,
  45.                 0,
  46.                 NULL,
  47.                 (HANDLE)0,
  48.                 NULL,
  49.                 Worker,
  50.                 NULL
  51.                 );
  52.         if (!NT_SUCCESS(ntStatus))
  53.         {
  54.                 return;
  55.         }
  56.         ntStatus =
  57.                 PsCreateSystemThread(//创建消费者线程
  58.                 &hThread2,
  59.                 0,
  60.                 NULL,
  61.                 (HANDLE)0,
  62.                 NULL,
  63.                 Consumer,
  64.                 NULL
  65.                 );
  66.         if (!NT_SUCCESS(ntStatus))
  67.         {
  68.                 return;
  69.         }
  70.         if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
  71.         {
  72.                 ntStatus = KfRaiseIrql(PASSIVE_LEVEL);
  73.         }
  74.         if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
  75.         {
  76.                 return;
  77.         }       
  78.         ntStatus = ObReferenceObjectByHandle(
  79.                 hThread1,
  80.                 THREAD_ALL_ACCESS,
  81.                 NULL,
  82.                 KernelMode,
  83.                 &objtowait[0],
  84.                 NULL
  85.                 );
  86.         if (!NT_SUCCESS(ntStatus))
  87.         {
  88.                 return;
  89.         }
  90.         ntStatus = ObReferenceObjectByHandle(
  91.                 hThread2,
  92.                 THREAD_ALL_ACCESS,
  93.                 NULL,
  94.                 KernelMode,
  95.                 &objtowait[1],
  96.                 NULL
  97.                 );
  98.         if (!NT_SUCCESS(ntStatus))
  99.         {
  100.                 ObDereferenceObject(objtowait[0]);
  101.                 return;
  102.         }
  103.         KeWaitForMultipleObjects(//等待两个线程结束
  104.                 2,
  105.                 objtowait,  
  106.                 WaitAll,
  107.                 Executive,
  108.                 KernelMode,
  109.                 FALSE,
  110.                 NULL,
  111.                 NULL);
  112.         ObDereferenceObject(objtowait[0]);
  113.         ObDereferenceObject(objtowait[1]);
  114.         //KeWaitForSingleObject(objtowait,Executive,KernelMode,FALSE,NULL);
  115.         return;
  116. }
  117. NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
  118. {
  119.         pDriverObject->DriverUnload = DriverUnload;
  120.         KeInitializeSemaphore(
  121.                 &g_kSemaphore,
  122.                 0,//信号量的初始值
  123.                 10 //信号量的最大值
  124.                 );
  125.         StartThreads();
  126.         return STATUS_SUCCESS;
  127. }
复制代码



二.互斥


1.KSPIN_LOCK


KSPIN_LOCK与Mutex的区别:
1.KSPIN_LOCK是忙等,不会阻塞系统,对忙等线程的调度则该线程会占着CPU不放,一直轮循
因此,Spinlock适用于等待时间不会太长(不超过25微妙)的情况.
而Mutex不是,它会系统阻塞请求线程,如果需要长时间范围一个对线,那么首先考虑使用互斥而不是自循锁


2.Spinlock请求成功之后,CPU的执行级别会提升到DL,Mutex不会.


3.DL及一线级别都可以使用Spinlock,而Mutex通常在PL请求,如果要在DL上则TIMEOUT需要设为0(只能试探一下)


4.Spinlock是“非递归锁” 不能递归获得该锁,而Mutex是“递归锁”


5.Spinlock主要用于多CUP,但效率不高,使用ERESOURCE较好.


KSPIN_LOCK 使用:
用于线程互斥
使用注意事项:
多CPU共享安全
提升IRQL到DPC
禁止访问分页内存
获得时间越短越好
使用方法:
//定义
  1. KIRQL                     OldIrql;
  2. KSPIN_LOCK           mySpinLockProc;
  3. //获得
  4. KeAcquireSpinLock(
  5.                 &mySpinLockProc,
  6.                 &OldIrql);
  7. //对数据进行操作和访问
  8. ……
  9. //释放
  10. KeReleaseSpinLock(
  11.                 &mySpinLockProc,
  12.                 OldIrql);
复制代码




2.ERESOURCE(读写共享锁)
  1. typedef struct _MY_LOCK
  2. {
  3.     ERESOURCE        m_Lock;//用于互斥
  4. }MY_LOCK;
  5. VOID __stdcall LockWrite(MY_LOCK* lpLock)
  6. {
  7.     KeEnterCriticalRegion();
  8.     ExAcquireResourceExclusiveLite(&lpLock->m_Lock, TRUE);
  9. }
  10. VOID __stdcall UnLockWrite(MY_LOCK* lpLock)
  11. {
  12.     ExReleaseResourceLite(&lpLock->m_Lock);
  13.     KeLeaveCriticalRegion();
  14. }
  15. VOID __stdcall LockRead(MY_LOCK* lpLock)
  16. {
  17.     KeEnterCriticalRegion();
  18.     ExAcquireResourceSharedLite(&lpLock->m_Lock, TRUE);
  19. }
  20. VOID __stdcall LockReadStarveWriter(MY_LOCK* lpLock)
  21. {
  22.     KeEnterCriticalRegion();
  23.     //读优先
  24.     ExAcquireSharedStarveExclusive(&lpLock->m_Lock, TRUE);
  25.     //写优先
  26.   //ExAcquireSharedWaitForExclusive
  27. }
  28. VOID __stdcall UnLockRead(MY_LOCK* lpLock)
  29. {
  30.     ExReleaseResourceLite(&lpLock->m_Lock);
  31.     KeLeaveCriticalRegion();
  32. }
  33. VOID __stdcall InitLock(MY_LOCK* lpLock)
  34. {
  35.     ExInitializeResourceLite(&lpLock->m_Lock);
  36. }
  37. VOID __stdcall DeleteLock(MY_LOCK* lpLock)
  38. {
  39.     ExDeleteResourceLite(&lpLock->m_Lock);
  40. }
  41. //ERESOURCE的使用
  42. LIST_ENTRY g_WaitList;
  43. MY_LOCK  g_WaitListLock;
  44. //DriverEntry里
  45. InitLock(&g_WaitListLock);
  46. //多线程环境里
  47. LockWrite(&g_WaitListLock);
  48. lpWaitEntry = LookupWaitEntryByID(&g_WaitList, lpReply->m_ulWaitID);                                               
  49. if (lpWaitEntry != NULL)
  50. {
  51.                 lpWaitEntry->m_bBlocked = lpReply->m_ulBlocked;
  52.                 KeSetEvent(&lpWaitEntry->m_ulWaitEvent, 0, FALSE);               
  53.                 return;
  54. }                                       
  55. UnLockWrite(&g_WaitListLock);
  56. //DriverUnload里
  57. DeleteLock(&g_WaitListLock);
复制代码

3.FAST_MUTEX
用于互斥
大于APC_LEVEL就不能使用了(PL AL可用)
不能递归获得锁
  1. FAST_MUTEX        gSfilterAttachLock
  2. ExInitializeFastMutex( &gSfilterAttachLock );
  3. ExAcquireFastMutex( &gSfilterAttachLock );
  4. ExAcquireFastMutex( &gSfilterAttachLock );//错 递归获得锁
  5. //Do something here
  6. ……
  7. ExReleaseFastMutex( &gSfilterAttachLock );
  8. ExReleaseFastMutex( &gSfilterAttachLock );
复制代码
例子:
  1. #include <ntddk.h>
  2. ULONG        g_ulTotal = 0;
  3. FAST_MUTEX g_fmLock;
  4. VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
  5. {
  6.         DbgPrint("Goodbye, driver\n");
  7. }
  8. VOID ThreadProc1(IN PVOID pContext)
  9. {
  10.         ULONG i = 0;
  11.         ExAcquireFastMutex(&g_fmLock);
  12.         g_ulTotal++;
  13.         DbgPrint("ThreadProc1:%x\n", g_ulTotal);
  14.         ExReleaseFastMutex(&g_fmLock);
  15. }
  16. VOID ThreadProc2(IN PVOID pContext)
  17. {
  18.         ULONG i = 0;
  19.         ExAcquireFastMutex(&g_fmLock);
  20.         g_ulTotal++;
  21.         DbgPrint("ThreadProc2:%x\n", g_ulTotal);
  22.         ExReleaseFastMutex(&g_fmLock);
  23.        
  24. }
  25. void StartThreads()
  26. {
  27.         HANDLE hThread1          = NULL;
  28.         HANDLE hThread2          = NULL;
  29.         PVOID  objtowait[2] = {NULL};
  30.         NTSTATUS ntStatus =
  31.                 PsCreateSystemThread(
  32.                 &hThread1,
  33.                 0,
  34.                 NULL,
  35.                 (HANDLE)0,
  36.                 NULL,
  37.                 ThreadProc1,
  38.                 NULL
  39.                 );
  40.         if (!NT_SUCCESS(ntStatus))
  41.         {
  42.                 return;
  43.         }
  44.         ntStatus =
  45.                 PsCreateSystemThread(
  46.                 &hThread2,
  47.                 0,
  48.                 NULL,
  49.                 (HANDLE)0,
  50.                 NULL,
  51.                 ThreadProc2,
  52.                 NULL
  53.                 );
  54.         if (!NT_SUCCESS(ntStatus))
  55.         {
  56.                 return;
  57.         }
  58.         if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
  59.         {
  60.                 ntStatus = KfRaiseIrql(PASSIVE_LEVEL);
  61.         }
  62.         if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
  63.         {
  64.                 return;
  65.         }       
  66.         ntStatus = ObReferenceObjectByHandle(
  67.                 hThread1,
  68.                 THREAD_ALL_ACCESS,
  69.                 NULL,
  70.                 KernelMode,
  71.                 &objtowait[0],
  72.                 NULL
  73.                 );
  74.         if (!NT_SUCCESS(ntStatus))
  75.         {
  76.                 return;
  77.         }
  78.         ntStatus = ObReferenceObjectByHandle(
  79.                 hThread1,
  80.                 THREAD_ALL_ACCESS,
  81.                 NULL,
  82.                 KernelMode,
  83.                 &objtowait[1],
  84.                 NULL
  85.                 );
  86.         if (!NT_SUCCESS(ntStatus))
  87.         {
  88.                 ObDereferenceObject(objtowait[0]);
  89.                 return;
  90.         }
  91.         KeWaitForMultipleObjects(
  92.                 2,
  93.                 objtowait,  
  94.                 WaitAll,
  95.                 Executive,
  96.                 KernelMode,
  97.                 FALSE,
  98.                 NULL,
  99.                 NULL);
  100.         ObDereferenceObject(objtowait[0]);
  101.         ObDereferenceObject(objtowait[1]);
  102.         //KeWaitForSingleObject(objtowait,Executive,KernelMode,FALSE,NULL);
  103.         return;
  104. }
  105. NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
  106. {
  107.         pDriverObject->DriverUnload = DriverUnload;
  108.         ExInitializeFastMutex(&g_fmLock);
  109.         StartThreads();
  110.         return STATUS_SUCCESS;
  111. }
复制代码

4.KMUTEX
基本淘汰,使用FAST_MUTEX取代
特点:
FAST_MUTEX无法递归,KMUTEX可以
FAST_MUTEX无法WAIT,KMUTEX可以
FAST_MUTEX 在APC LEVE,KMUTEX任意LEVEL
用法:
  1. KMUTEX mutex;
  2. KeInitializeMutex(
  3.             & mutex,
  4.             0
  5.                 );
  6. KeWaitForSingleObject(& mutex, Executive, KernelMode, FALSE, &MmOneSecond);
  7. KeReleaseMutex(& mutex, FALSE);
复制代码
总结:
DISPATCH_LEVEL:
SpinLock
APC/PASSIVE:
互斥:ERESOURCE/FAST_MUTEX
同步:KEVENT/KSEMAPHORE
R3/R0同步通信:
KEVENT
整数增减赋值:
InterlockedExchange 函数把第一个参数指向的内存地址的值,以原子的方式替换为第二个参数的值。并返回原来的值。InterlockedExchange函数还有8位,16位和64位的版本;
InterlockedIncrement/InterlockedDecrement 增加1/减少1 //在FAST_MUTEX的例子中可以用这个替换掉

R3多线程演示:
  1. ULONG WINAPI ThreadProc(void* arg)
  2. {
  3.     return 1;
  4. }
  5. VOID CreateThread()
  6. {
  7.         HANDLE hThread = NULL;
  8.         hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
  9.        
  10.         WaitForSingleObject(hThread, INFINITE);
  11.         CloseHandle(hThread);
  12.         hThread = NULL;
  13. }
  14. UINT WINAPI ThreadProc(LPVOID lpParameter)
  15. {
  16.             return 0;
  17. }
  18. VOID Beginthreadex()
  19. {
  20.         unsigned tid = 0;
  21.         HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0, ThreadProc,  NULL, 0, &tid);
  22.         WaitForSingleObject( hThread, INFINITE );
  23.         CloseHandle(hThread);
  24.         hThread = NULL;
  25. }
  26. UINT threadProc(LPVOID v)
  27. {
  28.         AfxEndThread(0);
  29. }
  30.        
  31. VOID AfxbeginThread()
  32. {
  33.          CWinThread *pThreadR  =         AfxBeginThread(threadProc,(LPVOID)param);
  34.         pThreadR->SuspendThread();
  35.         pThreadR->m_bAutoDelete = FALSE;
  36.         pThreadR->ResumeThread();
  37.         if (WaitForSingleObject(pThreadR->m_hThread,         2*1000)==WAIT_TIMEOUT)
  38.         {
  39.                 TerminateThread(pThreadR->m_hThread, 0);
  40.         }
  41.         delete (pThreadR);
  42.      pThreadR = NULL;
  43. }
复制代码


三个函数的区别
CreateThread:是Windows的API函数(SDK函数的标准形式,直截了当的创建方式,任何场合都可以使用),提供操作系统级别的创建线程的操作,且仅限于工作者线程。不调用MFC和RTL的函数时,可以用CreateThread,其它情况不要使用。因为:
C Runtime中需要对多线程进行纪录和初始化,以保证C函数库工作正常。
MFC也需要知道新线程的创建,也需要做一些初始化工作。
有些CRT的函数象malloc(),fopen(),_open(),strtok(),ctime(),或localtime()等函数需要专门的线程局部存储的数据块,这个数据块通常需要在创建线程的时候就建立,如果使用CreateThread,这个数据块就没有建立,但函数会自己建立一个,然后将其与线程联系在一起,这意味着如果你用CreateThread来创建线程,然后使用这样的函数,会有一块内存在不知不觉中创建,而且这些函数并不将其删除,而CreateThread和ExitThread也无法知道这件事,于是就会有Memory
  Leak,在线程频繁启动的软件中,迟早会让系统的内存资源耗尽。
_beginthreadex:MS对C Runtime库的扩展SDK函数,首先针对C Runtime库做了一些初始化的工作,以保证C Runtime库工作正常。然后,调用CreateThread真正创建线程。
AfxBeginThread:MFC中线程创建的MFC函数,首先创建了相应的CWinThread对象,然后调用CWinThread::CreateThread,在CWinThread::CreateThread中,完成了对线程对象的初始化工作,然后,调用_beginthreadex(AfxBeginThread相比较更为安全)创建线程。它让线程能够响应消息,可用于界面线程,也可以用于工作者线程。




三个函数的应用条件
AfxBeginThread:在MFC中用,工作者线程/界面线程
_beginthreadex: 调用了C运行库的,应该用这个,但不能用在MFC中。
CreateThread:工作者线程,MFC中不能用,C Runtime中不能用。所以任何时候最好都不要用。



R3多线程总结:
Critical Section/Mutex/Semap
Critical_sectionhore/Event
1. Critical Section与Mutex作用非常相似,但Mutex是可以命名的,也就是说它可以跨越进程使用。所以创建互斥量需要的资源更多,如果只为了在进程内部使用的话,使用临界区会带来速度上的优势并能够减少资源占用量。因为互斥量是跨进程的,互斥量一旦被创建,就可以通过名字打开它。
2.互斥量(Mutex),信号量(Semaphore),事件(Event)都可以跨越进程来进行同步数据操作(一个进程创建之后,另外的进程可以通过名字打开它,从而用于进程间的数据同步)
3.通过Mutex可以指定资源被独占的方式使用,但如果一个资源允许N(N>1)个进程或者线程访问,这时候如果利用Mutex就没有办法完成这个要求, Semaphore可以,是一种资源计数器。


Critical_section
struct RTL_CRITICAL_SECTION
{
  PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
  LONG LockCount;
  LONG RecursionCount;
  HANDLE OwningThread;
  HANDLE LockSemaphore;
  ULONG_PTR SpinCount;
};
DebugInfo 此字段包含一个指针,指向系统分配的伴随结构,该结构的类型为
RTL_CRITICAL_SECTION_DEBUG
LockCount 这是临界区中最重要的一个字段。它被初始化为数值 -1;此数值等于或大于 0 时,表示此临界区被占用。当其不等于 -1 时,OwningThread 字段包含了拥有此临界区的线程 ID。此字段与 (RecursionCount -1) 数值之间的差值表示有多少个其他线程在等待获得该临界区。
RecursionCount 此字段包含所有者线程已经获得该临界区的次数。如果该数值为零,下一个尝试获取该临界区的线程将会成功。
OwningThread 此字段包含当前占用此临界区的线程的线程标识符。此线程 ID 与 GetCurrentThreadId 之类的 API 所返回的 ID 相同。
LockSemaphore 它实际上是一个自复位事件,而不是一个信号。它是一个内核对象句柄,用于通知操作系统:该临界区现在空闲。操作系统在一个线程第一次尝试获得该临界区,但被另一个已经拥有该临界区的线程所阻止时,自动创建这样一个句柄。应当调用 DeleteCriticalSection(它将发出一个调用该事件的 CloseHandle 调用,并在必要时释放该调试结构),否则将会发生资源泄漏。
SpinCount 仅用于多处理器系统。在多处理器系统中,如果该临界区不可用,调用线程将在对与该临界区相关的信号执行等待操作之前,旋转 dwSpinCount 次。如果该临界区在旋转操作期间变为可用,该调用线程就避免了等待操作。旋转计数可以在多处理器计算机上提供更佳性能,其原因在于在一个循环中旋转通常要快于进入内核模式等待状态。此字段默认值为零,但可以用InitializeCriticalSectionAndSpinCount API 将其设置为一个不同值。




三.实现自动加锁 使用C++的构造和析构函数


CAutoLocker
  1. class CLock
  2. {
  3. public:
  4.         void Lock() {EnterCriticalSection(&m_sec);}
  5.         void Unlock() {LeaveCriticalSection(&m_sec);}
  6.         CLock () {InitializeCriticalSection(&m_sec);}
  7.         ~ CLock () {DeleteCriticalSection(&m_sec);}       
  8. private:
  9.     CRITICAL_SECTION m_sec;
  10. };
  11. class CAutoLock
  12. {
  13. public:
  14.       CAutoLock(CLock  * lpLock) :
  15.       m_pLock (lpLock)
  16.       {
  17.           m_pLock ->Lock();
  18.       }
  19.       ~CAutoLock()
  20.       {
  21.           m_pLock ->Unlock();
  22.       }
  23. private:
  24.     CLock * m_pLock;
  25. };
复制代码




使用例子:
  1. {
  2.     CLock m_lock;
  3.     CAutoLock(&m_lock);
  4.     ….
  5. }
复制代码
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-3-19 13:04

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表