多线程 以及多线程安全

线程的运行级别(IRQL)


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


引用来自http://blog.csdn.net/fengkuangfj/article/details/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()宏
[cpp]  view plain  copy
  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级




内核多线程创建演示
[cpp]  view plain  copy
  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演示:
[cpp]  view plain  copy
  1.  LARGE_INTEGER TimeOut =  {0};  
  2. TimeOut.QuadPart = -10 * 10000000i64;//10s  
  3.   
  4.   
  5. KeWaitForSingleObject(  &kSemaphore,   
  6.     Executive,   
  7.     KernelMode,   
  8.     FALSE,   
  9.     &TimeOut//0,不等;NULL,无限等待  
  10.     );  

同步:
一.KEVENT
用于线程同步
Event两个状态:
Signaled 
Non-signaled
Event两个类别:
Notification事件:不自动恢复
synchronization事件:自动恢复


创建:IoCreateNotificationEvent //创建一个有名字的事件 供其它进程 或R3 R0通信

[cpp]  view plain  copy
  1. KEVENT waitEvent;  
  2. KeInitializeEvent(&waitEvent,  
  3.                NotificationEvent,  
  4.                FALSE );  
  5. //开灯  
  6. KeSetEvent(&waitEvent,   
  7.     IO_NO_INCREMENT,   
  8.     FALSE );  
  9.   
  10.   
  11. //等灯  
  12. KeWaitForSingleObject(   
  13.             &waitEvent,  
  14.                     Executive,  
  15.                     KernelMode,  
  16.                     FALSE,  
  17.                     NULL );//0,立即返回;  
  18.                         //NULL无限等待  
  19.   
  20.   
  21. //关灯  
  22. KeClearEvent(&waitEvent);  
  23. KeResetEvent(&waitEvent);  


例子:进程创建监视:R0到R3同步通信 这个例子在xp和win7中的效果是不同的,xp上只要得到了信号就会退出,win7不会 原因:

-------------------------------------------------------------------------------------------------------

在XP中创建一个进程就退出 原因是WaitForSingleObject 等待成功后返回0
而在win7中 WaitForSingleObject  等待成功后返回0xffffffff;

------------------------------------------------------------------------------------------------------

Event创建:

[cpp]  view plain  copy
  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->ProcessEvent, 0, FALSE);
KeClearEvent(deviceExtension->ProcessEvent);


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:

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

R0:

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

注意了 上面这个工程中有个循环 ,循环中有个变量时test 这个变量在xp下 一般返回0 在win7 下返回0xffffffff;

这个代码没有改之前是

[cpp]  view plain  copy
  1. while (::WaitForSingleObject(hProcessEvent, INFINITE))  
  2. {  
  3.     ....  
这会影响循环是否keep runing


2.KSEMAPHORE
比如工作者与消费者之间  工作者增加一个资源 消费者才能买一个 消费者买了一个 就减少一个资源
用于同步与多个资源共享访问
[cpp]  view plain  copy
  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 );  


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




二.互斥


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
禁止访问分页内存
获得时间越短越好
使用方法:
//定义
[cpp]  view plain  copy
  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(读写共享锁) 
[cpp]  view plain  copy
  1. typedef struct _MY_LOCK  
  2. {  
  3.     ERESOURCE   m_Lock;//用于互斥  
  4. }MY_LOCK;  
  5.   
  6.   
  7. VOID __stdcall LockWrite(MY_LOCK* lpLock)  
  8. {  
  9.     KeEnterCriticalRegion();  
  10.     ExAcquireResourceExclusiveLite(&lpLock->m_Lock, TRUE);  
  11. }  
  12.   
  13.   
  14. VOID __stdcall UnLockWrite(MY_LOCK* lpLock)  
  15. {  
  16.     ExReleaseResourceLite(&lpLock->m_Lock);  
  17.     KeLeaveCriticalRegion();  
  18. }  
  19. VOID __stdcall LockRead(MY_LOCK* lpLock)  
  20. {  
  21.     KeEnterCriticalRegion();  
  22.     ExAcquireResourceSharedLite(&lpLock->m_Lock, TRUE);  
  23. }  
  24.   
  25.   
  26. VOID __stdcall LockReadStarveWriter(MY_LOCK* lpLock)  
  27. {  
  28.     KeEnterCriticalRegion();  
  29.     //读优先  
  30.     ExAcquireSharedStarveExclusive(&lpLock->m_Lock, TRUE);  
  31.     //写优先  
  32.   //ExAcquireSharedWaitForExclusive   
  33. }  
  34. VOID __stdcall UnLockRead(MY_LOCK* lpLock)  
  35. {  
  36.     ExReleaseResourceLite(&lpLock->m_Lock);  
  37.     KeLeaveCriticalRegion();  
  38. }  
  39.   
  40.   
  41. VOID __stdcall InitLock(MY_LOCK* lpLock)  
  42. {  
  43.     ExInitializeResourceLite(&lpLock->m_Lock);  
  44. }  
  45.   
  46.   
  47. VOID __stdcall DeleteLock(MY_LOCK* lpLock)  
  48. {  
  49.     ExDeleteResourceLite(&lpLock->m_Lock);  
  50. }  
  51.   
  52.   
  53. //ERESOURCE的使用  
  54. LIST_ENTRY g_WaitList;  
  55. MY_LOCK  g_WaitListLock;  
  56. //DriverEntry里  
  57. InitLock(&g_WaitListLock);  
  58.   
  59.   
  60. //多线程环境里  
  61. LockWrite(&g_WaitListLock);  
  62. lpWaitEntry = LookupWaitEntryByID(&g_WaitList, lpReply->m_ulWaitID);                       
  63. if (lpWaitEntry != NULL)  
  64. {  
  65.         lpWaitEntry->m_bBlocked = lpReply->m_ulBlocked;  
  66.         KeSetEvent(&lpWaitEntry->m_ulWaitEvent, 0, FALSE);         
  67.         return;  
  68. }                     
  69. UnLockWrite(&g_WaitListLock);  
  70.   
  71.   
  72. //DriverUnload里  
  73. DeleteLock(&g_WaitListLock);  


3.FAST_MUTEX
用于互斥
大于APC_LEVEL就不能使用了(PL AL可用)
不能递归获得锁

[cpp]  view plain  copy
  1. FAST_MUTEX  gSfilterAttachLock  
  2. ExInitializeFastMutex( &gSfilterAttachLock );  
  3.   
  4.   
  5. ExAcquireFastMutex( &gSfilterAttachLock );  
  6. ExAcquireFastMutex( &gSfilterAttachLock );//错 递归获得锁  
  7. //Do something here  
  8. ……  
  9. ExReleaseFastMutex( &gSfilterAttachLock );  
  10. ExReleaseFastMutex( &gSfilterAttachLock );  

例子:
[cpp]  view plain  copy
  1. #include <ntddk.h>  
  2.   
  3.   
  4. ULONG   g_ulTotal = 0;  
  5. FAST_MUTEX g_fmLock;  
  6.   
  7.   
  8. VOID DriverUnload(PDRIVER_OBJECT pDriverObject)  
  9. {  
  10.     DbgPrint("Goodbye, driver\n");  
  11. }  
  12.   
  13.   
  14. VOID ThreadProc1(IN PVOID pContext)  
  15. {  
  16.     ULONG i = 0;  
  17.     ExAcquireFastMutex(&g_fmLock);  
  18.   
  19.   
  20.     g_ulTotal++;  
  21.     DbgPrint("ThreadProc1:%x\n", g_ulTotal);  
  22.   
  23.   
  24.   
  25.   
  26.     ExReleaseFastMutex(&g_fmLock);  
  27.   
  28.   
  29. }  
  30.   
  31.   
  32. VOID ThreadProc2(IN PVOID pContext)  
  33. {  
  34.     ULONG i = 0;  
  35.     ExAcquireFastMutex(&g_fmLock);  
  36.   
  37.   
  38.     g_ulTotal++;  
  39.     DbgPrint("ThreadProc2:%x\n", g_ulTotal);  
  40.   
  41.   
  42.     ExReleaseFastMutex(&g_fmLock);  
  43.       
  44. }  
  45.   
  46.   
  47. void StartThreads()  
  48. {  
  49.     HANDLE hThread1      = NULL;  
  50.     HANDLE hThread2      = NULL;  
  51.   
  52.   
  53.     PVOID  objtowait[2] = {NULL};  
  54.     NTSTATUS ntStatus =   
  55.         PsCreateSystemThread(  
  56.         &hThread1,  
  57.         0,  
  58.         NULL,  
  59.         (HANDLE)0,  
  60.         NULL,  
  61.         ThreadProc1,  
  62.         NULL  
  63.         );  
  64.     if (!NT_SUCCESS(ntStatus))  
  65.     {  
  66.         return;  
  67.     }  
  68.   
  69.   
  70.     ntStatus =   
  71.         PsCreateSystemThread(  
  72.         &hThread2,  
  73.         0,  
  74.         NULL,  
  75.         (HANDLE)0,  
  76.         NULL,  
  77.         ThreadProc2,  
  78.         NULL  
  79.         );  
  80.     if (!NT_SUCCESS(ntStatus))  
  81.     {  
  82.         return;  
  83.     }  
  84.   
  85.   
  86.     if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)  
  87.     {  
  88.         ntStatus = KfRaiseIrql(PASSIVE_LEVEL);  
  89.     }  
  90.     if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)  
  91.     {  
  92.         return;  
  93.     }     
  94.     ntStatus = ObReferenceObjectByHandle(  
  95.         hThread1,  
  96.         THREAD_ALL_ACCESS,  
  97.         NULL,  
  98.         KernelMode,  
  99.         &objtowait[0],  
  100.         NULL  
  101.         );   
  102.     if (!NT_SUCCESS(ntStatus))  
  103.     {  
  104.         return;  
  105.     }  
  106.   
  107.   
  108.     ntStatus = ObReferenceObjectByHandle(  
  109.         hThread1,  
  110.         THREAD_ALL_ACCESS,  
  111.         NULL,  
  112.         KernelMode,  
  113.         &objtowait[1],  
  114.         NULL  
  115.         );   
  116.     if (!NT_SUCCESS(ntStatus))  
  117.     {  
  118.         ObDereferenceObject(objtowait[0]);  
  119.         return;  
  120.     }  
  121.   
  122.   
  123.     KeWaitForMultipleObjects(  
  124.         2,   
  125.         objtowait,    
  126.         WaitAll,  
  127.         Executive,  
  128.         KernelMode,  
  129.         FALSE,  
  130.         NULL,  
  131.         NULL);  
  132.   
  133.   
  134.     ObDereferenceObject(objtowait[0]);  
  135.     ObDereferenceObject(objtowait[1]);  
  136.   
  137.   
  138.     //KeWaitForSingleObject(objtowait,Executive,KernelMode,FALSE,NULL);   
  139.     return;  
  140. }  
  141.   
  142.   
  143.   
  144.   
  145.   
  146.   
  147. NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)  
  148. {  
  149.     pDriverObject->DriverUnload = DriverUnload;  
  150.   
  151.   
  152.     ExInitializeFastMutex(&g_fmLock);  
  153.   
  154.   
  155.     StartThreads();  
  156.   
  157.   
  158.   
  159.   
  160.     return STATUS_SUCCESS;  
  161. }  


4.KMUTEX 
基本淘汰,使用FAST_MUTEX取代
特点:
FAST_MUTEX无法递归,KMUTEX可以
FAST_MUTEX无法WAIT,KMUTEX可以
FAST_MUTEX 在APC LEVE,KMUTEX任意LEVEL
用法:
[cpp]  view plain  copy
  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多线程演示:

[cpp]  view plain  copy
  1. ULONG WINAPI ThreadProc(void* arg)  
  2. {  
  3.     return 1;  
  4. }  
  5.   
  6.   
  7. VOID CreateThread()  
  8. {  
  9.     HANDLE hThread = NULL;  
  10.   
  11.   
  12.     hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);  
  13.       
  14.     WaitForSingleObject(hThread, INFINITE);  
  15.     CloseHandle(hThread);  
  16.     hThread = NULL;  
  17. }  
  18.   
  19.   
  20.   
  21.   
  22.   
  23.   
  24. UINT WINAPI ThreadProc(LPVOID lpParameter)  
  25. {  
  26.         return 0;  
  27. }  
  28.   
  29.   
  30. VOID Beginthreadex()  
  31. {  
  32.     unsigned tid = 0;  
  33.     HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0, ThreadProc,  NULL, 0, &tid);  
  34.     WaitForSingleObject( hThread, INFINITE );  
  35.     CloseHandle(hThread);  
  36.     hThread = NULL;  
  37. }  
  38.   
  39.   
  40.   
  41.   
  42.   
  43.   
  44. UINT threadProc(LPVOID v)  
  45. {  
  46.     AfxEndThread(0);  
  47. }  
  48.       
  49. VOID AfxbeginThread()  
  50. {  
  51.      CWinThread *pThreadR  =    AfxBeginThread(threadProc,(LPVOID)param);  
  52.     pThreadR->SuspendThread();  
  53.     pThreadR->m_bAutoDelete = FALSE;  
  54.     pThreadR->ResumeThread();  
  55.   
  56.   
  57.     if (WaitForSingleObject(pThreadR->m_hThread,     2*1000)==WAIT_TIMEOUT)  
  58.     {  
  59.         TerminateThread(pThreadR->m_hThread, 0);  
  60.     }  
  61.     delete (pThreadR);  
  62.      pThreadR = NULL;  
  63. }  



三个函数的区别
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 

[cpp]  view plain  copy
  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.   
  12.   
  13. class CAutoLock  
  14. {  
  15. public:  
  16.       CAutoLock(CLock  * lpLock) :  
  17.       m_pLock (lpLock)  
  18.       {  
  19.           m_pLock ->Lock();  
  20.       }  
  21.       ~CAutoLock()  
  22.       {  
  23.           m_pLock ->Unlock();  
  24.       }  
  25. private:  
  26.     CLock * m_pLock;  
  27. };  





使用例子:
[cpp]  view plain  copy
  1. {  
  2.     CLock m_lock;  
  3.     CAutoLock(&m_lock);  
  4.     ….  
  5. }  











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值