线程的运行级别(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()宏
一般的
DriverEntry,DriverUnload Passive级
各种分发函数 Passive级
完成函数 DL级
各种NDIS回调函数 DL级
内核多线程创建演示
同步互斥
互斥(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演示:
同步:
一.KEVENT
用于线程同步
Event两个状态:
Signaled
Non-signaled
Event两个类别:
Notification事件:不自动恢复
synchronization事件:自动恢复
创建:IoCreateNotificationEvent //创建一个有名字的事件 供其它进程 或R3 R0通信
数据存放:使用设备扩展 详细使用方法见下面完整代码
定义
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下去拿数据
}
R0:
这会影响循环是否keep runing
2.KSEMAPHORE
比如工作者与消费者之间 工作者增加一个资源 消费者才能买一个 消费者买了一个 就减少一个资源
用于同步与多个资源共享访问
例子:工作者 与 消费者
二.互斥
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
禁止访问分页内存
获得时间越短越好
使用方法:
//定义
2.ERESOURCE(读写共享锁)
3.FAST_MUTEX
用于互斥
大于APC_LEVEL就不能使用了(PL AL可用)
不能递归获得锁
例子:
4.KMUTEX
基本淘汰,使用FAST_MUTEX取代
特点:
FAST_MUTEX无法递归,KMUTEX可以
FAST_MUTEX无法WAIT,KMUTEX可以
FAST_MUTEX 在APC LEVE,KMUTEX任意LEVEL
用法:
总结:
DISPATCH_LEVEL:
SpinLock
APC/PASSIVE:
互斥:ERESOURCE/FAST_MUTEX
同步:KEVENT/KSEMAPHORE
R3/R0同步通信:
KEVENT
整数增减赋值:
InterlockedExchange 函数把第一个参数指向的内存地址的值,以原子的方式替换为第二个参数的值。并返回原来的值。InterlockedExchange函数还有8位,16位和64位的版本;
InterlockedIncrement/InterlockedDecrement 增加1/减少1 //在FAST_MUTEX的例子中可以用这个替换掉
三个函数的区别
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中不能用。所以任何时候最好都不要用。
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
使用例子:
中断是指在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()宏
- #define PAGED_CODE() \
- { if (KeGetCurrentIrql() > APC_LEVEL) { \
- KdPrint(( "EX: Pageable code called at IRQL %d\n", KeGetCurrentIrql() )); \
- ASSERT(FALSE); \
- } \
- }
一般的
DriverEntry,DriverUnload Passive级
各种分发函数 Passive级
完成函数 DL级
各种NDIS回调函数 DL级
内核多线程创建演示
- VOID DoFind(IN PVOID pContext)
- {
- }
- void StartThread()
- {
- HANDLE hThread = NULL;
- PVOID objtowait = 0;
- NTSTATUS dwStatus =
- PsCreateSystemThread(
- &hThread,
- 0,
- NULL,
- (HANDLE)0,
- NULL,
- DoFind,
- NULL
- );
- if (!NT_SUCCESS(dwStatus)
- {
- return;
- }
- if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
- {
- dwStatus=KfRaiseIrql(PASSIVE_LEVEL);
- }
- if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
- {
- return;
- }
- ObReferenceObjectByHandle(
- hThread,
- THREAD_ALL_ACCESS,
- NULL,
- KernelMode,
- &objtowait,
- NULL
- );
- KeWaitForSingleObject(objtowait,Executive,KernelMode,FALSE,NULL);
- <span style="font-family: 'Courier New'; line-height: 18px; white-space: pre-wrap;">ObDereferenceObject</span>(objtowait);
- return;
- }
同步互斥
互斥(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演示:
- LARGE_INTEGER TimeOut = {0};
- TimeOut.QuadPart = -10 * 10000000i64;//10s
- KeWaitForSingleObject( &kSemaphore,
- Executive,
- KernelMode,
- FALSE,
- &TimeOut//0,不等;NULL,无限等待
- );
同步:
一.KEVENT
用于线程同步
Event两个状态:
Signaled
Non-signaled
Event两个类别:
Notification事件:不自动恢复
synchronization事件:自动恢复
创建:IoCreateNotificationEvent //创建一个有名字的事件 供其它进程 或R3 R0通信
- KEVENT waitEvent;
- KeInitializeEvent(&waitEvent,
- NotificationEvent,
- FALSE );
- //开灯
- KeSetEvent(&waitEvent,
- IO_NO_INCREMENT,
- FALSE );
- //等灯
- KeWaitForSingleObject(
- &waitEvent,
- Executive,
- KernelMode,
- FALSE,
- NULL );//0,立即返回;
- //NULL无限等待
- //关灯
- KeClearEvent(&waitEvent);
- KeResetEvent(&waitEvent);
例子:进程创建监视:R0到R3同步通信 这个例子在xp和win7中的效果是不同的,xp上只要得到了信号就会退出,win7不会 原因:
-------------------------------------------------------------------------------------------------------
在XP中创建一个进程就退出 原因是WaitForSingleObject 等待成功后返回0
而在win7中 WaitForSingleObject 等待成功后返回0xffffffff;
------------------------------------------------------------------------------------------------------
Event创建:
- L\\BaseNamedObjects\\ProcEvent
- 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:
- // ProcWatchClientConsole.cpp : Defines the entry point for the console application.
- //
- //#include "stdafx.h"
- #include "windows.h"
- #include "winioctl.h"
- #include "stdio.h"
- BOOL LoadDriver(char* lpszDriverName,char* lpszDriverPath);
- BOOL UnloadDriver(char * szSvrName);
- #define EVENT_NAME L"ProcEvent"
- #define DRIVER_NAME "ProcWatch"
- #define DRIVER_PATH ".\\ProcWatch.sys"
- #pragma comment(lib,"Advapi32.lib")
- #define CTRLCODE_BASE 0x8000
- #define MYCTRL_CODE(i) \
- CTL_CODE(FILE_DEVICE_UNKNOWN,CTRLCODE_BASE + i, METHOD_BUFFERED, FILE_ANY_ACCESS)
- #define IOCTL_PROCWATCH MYCTRL_CODE(0)
- typedef struct _ProcMonData
- {
- HANDLE hParentId;
- HANDLE hProcessId;
- BOOLEAN bCreate;
- }ProcMonData, *PProcMonData;
- int main(int argc, char* argv[])
- {
- ProcMonData pmdInfoNow = {0};
- ProcMonData pmdInfoBefore = {0};
- if (!LoadDriver(DRIVER_NAME, DRIVER_PATH))
- {
- printf("LoadDriver Failed:%x\n", GetLastError());
- return -1;
- }
- // 打开驱动设备对象
- HANDLE hDriver = ::CreateFile(
- "\\\\.\\ProcWatch",
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (hDriver == INVALID_HANDLE_VALUE)
- {
- printf("Open device failed:%x\n", GetLastError());
- UnloadDriver(DRIVER_NAME);
- return -1;
- }
- // 打开内核事件对象
- HANDLE hProcessEvent = ::OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);
- //while (TRUE)
- //{
- //DWORD dwRet = 0;
- //BOOL bRet = FALSE;
- //::WaitForSingleObject(hProcessEvent, INFINITE);
- //WAIT_OBJECT_0
- //WAIT_TIMEOUT
- while (1)
- {
- ULONG test = ::WaitForSingleObject(hProcessEvent, INFINITE);
- Sleep(100);
- DWORD dwRet = 0;
- BOOL bRet = FALSE;
- bRet = ::DeviceIoControl(
- hDriver,
- IOCTL_PROCWATCH,
- NULL,
- 0,
- &pmdInfoNow,
- sizeof(pmdInfoNow),
- &dwRet,
- NULL);
- if (bRet)
- {
- if (pmdInfoNow.hParentId != pmdInfoBefore.hParentId || \
- pmdInfoNow.hProcessId != pmdInfoBefore.hProcessId || \
- pmdInfoNow.bCreate != pmdInfoBefore.bCreate)
- {
- if (pmdInfoNow.bCreate)
- {
- printf("ProcCreated,PID = %d\n", pmdInfoNow.hProcessId);
- }
- else
- {
- printf("ProcTeminated,PID = %d\n", pmdInfoNow.hProcessId);
- }
- pmdInfoBefore = pmdInfoNow;
- }
- }
- else
- {
- printf("Get Proc Info Failed!\n");
- break;
- }
- }
- ::CloseHandle(hDriver);
- UnloadDriver(DRIVER_NAME);
- return 0;
- }
- //装载NT驱动程序
- BOOL LoadDriver(char* lpszDriverName,char* lpszDriverPath)
- {
- char szDriverImagePath[256] = {0};
- //得到完整的驱动路径
- GetFullPathName(lpszDriverPath, 256, szDriverImagePath, NULL);
- BOOL bRet = FALSE;
- SC_HANDLE hServiceMgr=NULL;//SCM管理器的句柄
- SC_HANDLE hServiceDDK=NULL;//NT驱动程序的服务句柄
- //打开服务控制管理器
- hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
- if( hServiceMgr == NULL )
- {
- //OpenSCManager失败
- printf( "OpenSCManager() Faild %d ! \n", GetLastError() );
- bRet = FALSE;
- goto BeforeLeave;
- }
- else
- {
- OpenSCManager成功
- printf( "OpenSCManager() ok ! \n" );
- }
- //创建驱动所对应的服务
- hServiceDDK = CreateService( hServiceMgr,
- lpszDriverName, //驱动程序的在注册表中的名字
- lpszDriverName, // 注册表驱动程序的 DisplayName 值
- SERVICE_ALL_ACCESS, // 加载驱动程序的访问权限
- SERVICE_KERNEL_DRIVER,// 表示加载的服务是驱动程序
- SERVICE_DEMAND_START, // 注册表驱动程序的 Start 值
- SERVICE_ERROR_IGNORE, // 注册表驱动程序的 ErrorControl 值
- szDriverImagePath, // 注册表驱动程序的 ImagePath 值
- NULL, //GroupOrder HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GroupOrderList
- NULL,
- NULL,
- NULL,
- NULL);
- DWORD dwRtn;
- //判断服务是否失败
- if( hServiceDDK == NULL )
- {
- dwRtn = GetLastError();
- if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_EXISTS )
- {
- //由于其他原因创建服务失败
- printf( "CrateService() Faild %d ! \n", dwRtn );
- bRet = FALSE;
- goto BeforeLeave;
- }
- else
- {
- //服务创建失败,是由于服务已经创立过
- printf( "CrateService() Faild Service is ERROR_IO_PENDING or ERROR_SERVICE_EXISTS! \n" );
- }
- // 驱动程序已经加载,只需要打开
- hServiceDDK = OpenService( hServiceMgr, lpszDriverName, SERVICE_ALL_ACCESS );
- if( hServiceDDK == NULL )
- {
- //如果打开服务也失败,则意味错误
- dwRtn = GetLastError();
- printf( "OpenService() Faild %d ! \n", dwRtn );
- bRet = FALSE;
- goto BeforeLeave;
- }
- else
- {
- printf( "OpenService() ok ! \n" );
- }
- }
- else
- {
- printf( "CrateService() ok ! \n" );
- }
- //开启此项服务
- bRet= StartService( hServiceDDK, NULL, NULL );
- if( !bRet )
- {
- DWORD dwRtn = GetLastError();
- if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_ALREADY_RUNNING )
- {
- printf( "StartService() Faild %d ! \n", dwRtn );
- bRet = FALSE;
- goto BeforeLeave;
- }
- else
- {
- if( dwRtn == ERROR_IO_PENDING )
- {
- //设备被挂住
- printf( "StartService() Faild ERROR_IO_PENDING ! \n");
- bRet = FALSE;
- goto BeforeLeave;
- }
- else
- {
- //服务已经开启
- printf( "StartService() Faild ERROR_SERVICE_ALREADY_RUNNING ! \n");
- bRet = TRUE;
- goto BeforeLeave;
- }
- }
- }
- bRet = TRUE;
- //离开前关闭句柄
- BeforeLeave:
- getchar();
- if(hServiceDDK)
- {
- CloseServiceHandle(hServiceDDK);
- }
- if(hServiceMgr)
- {
- CloseServiceHandle(hServiceMgr);
- }
- return bRet;
- }
- //卸载驱动程序
- BOOL UnloadDriver( char * szSvrName )
- {
- BOOL bRet = FALSE;
- SC_HANDLE hServiceMgr=NULL;//SCM管理器的句柄
- SC_HANDLE hServiceDDK=NULL;//NT驱动程序的服务句柄
- SERVICE_STATUS SvrSta;
- //打开SCM管理器
- hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
- if( hServiceMgr == NULL )
- {
- //带开SCM管理器失败
- printf( "OpenSCManager() Faild %d ! \n", GetLastError() );
- bRet = FALSE;
- goto BeforeLeave;
- }
- else
- {
- //带开SCM管理器失败成功
- printf( "OpenSCManager() ok ! \n" );
- }
- //打开驱动所对应的服务
- hServiceDDK = OpenService( hServiceMgr, szSvrName, SERVICE_ALL_ACCESS );
- if( hServiceDDK == NULL )
- {
- //打开驱动所对应的服务失败
- printf( "OpenService() Faild %d ! \n", GetLastError() );
- bRet = FALSE;
- goto BeforeLeave;
- }
- else
- {
- printf( "OpenService() ok ! \n" );
- }
- //停止驱动程序,如果停止失败,只有重新启动才能,再动态加载。
- if( !ControlService( hServiceDDK, SERVICE_CONTROL_STOP , &SvrSta ) )
- {
- printf( "ControlService() Faild %d !\n", GetLastError() );
- }
- else
- {
- //打开驱动所对应的失败
- printf( "ControlService() ok !\n" );
- }
- //动态卸载驱动程序。
- if( !DeleteService( hServiceDDK ) )
- {
- //卸载失败
- printf( "DeleteSrevice() Faild %d !\n", GetLastError() );
- }
- else
- {
- //卸载成功
- printf( "DelServer:deleteSrevice() ok !\n" );
- }
- bRet = TRUE;
- BeforeLeave:
- //离开前关闭打开的句柄
- if(hServiceDDK)
- {
- CloseServiceHandle(hServiceDDK);
- }
- if(hServiceMgr)
- {
- CloseServiceHandle(hServiceMgr);
- }
- return bRet;
- }
R0:
- #include "ntddk.h"
- #include "windef.h"
- #define EVENT_NAME L"\\BaseNamedObjects\\ProcEvent"
- #define DEVICE_NAME L"\\Device\\ProcWatch"
- #define LINK_NAME L"\\DosDevices\\ProcWatch"
- #define CTRLCODE_BASE 0x8000
- #define MYCTRL_CODE(i) \
- CTL_CODE(FILE_DEVICE_UNKNOWN,CTRLCODE_BASE + i, METHOD_BUFFERED, FILE_ANY_ACCESS)
- #define IOCTL_PROCWATCH MYCTRL_CODE(0)
- typedef struct _ProcMonData
- {
- HANDLE hParentId;
- HANDLE hProcessId;
- BOOLEAN bCreate;
- }ProcMonData, *PProcMonData;
- VOID DriverUnload(IN PDRIVER_OBJECT DriverObject);
- NTSTATUS CommonDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
- NTSTATUS IoctrlDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
- VOID ProcessCreateMon( IN HANDLE hParentId, IN HANDLE PId, IN BOOLEAN bCreate);
- typedef struct _DEVICE_EXTENSION
- {
- HANDLE hProcessHandle; // 事件对象句柄
- PKEVENT ProcessEvent; // 用户和内核通信的事件对象指针
- HANDLE hParentId; // 在回调函数中保存进程信息
- HANDLE hProcessId;
- BOOLEAN bCreate;
- } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
- PDEVICE_OBJECT g_pDeviceObject = NULL;
- // 驱动入口
- NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
- {
- UNICODE_STRING ustrDeviceName = {0};
- UNICODE_STRING ustrLinkName = {0};
- PDEVICE_OBJECT deviceObject = NULL;
- NTSTATUS status = STATUS_SUCCESS;
- int i = 0;
- UNICODE_STRING ustrEventStr = {0};
- PDEVICE_EXTENSION pDeviceExtension = NULL;
- //建立设备
- RtlInitUnicodeString( &ustrDeviceName, DEVICE_NAME );
- status = IoCreateDevice( DriverObject,
- sizeof(DEVICE_EXTENSION),
- &ustrDeviceName,
- FILE_DEVICE_UNKNOWN,
- 0,
- FALSE,
- &deviceObject
- );
- if (!NT_SUCCESS( status ))
- {
- return status;
- }
- deviceObject->Flags |= DO_BUFFERED_IO;
- g_pDeviceObject = deviceObject;
- // 创建事件对象与应用层通信
- RtlInitUnicodeString(&ustrEventStr, EVENT_NAME);
- pDeviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
- pDeviceExtension->ProcessEvent =
- IoCreateNotificationEvent(&ustrEventStr,
- &pDeviceExtension->hProcessHandle);
- KeClearEvent(pDeviceExtension->ProcessEvent); // 设置为非受信状态
- RtlInitUnicodeString( &ustrLinkName, LINK_NAME);
- status = IoCreateSymbolicLink(&ustrLinkName, &ustrDeviceName);
- if (!NT_SUCCESS( status ))
- {
- IoDeleteDevice(DriverObject->DeviceObject);
- return status;
- }
- status = PsSetCreateProcessNotifyRoutine(ProcessCreateMon, FALSE);
- if (!NT_SUCCESS( status ))
- {
- IoDeleteDevice(DriverObject->DeviceObject);
- DbgPrint("PsSetCreateProcessNotifyRoutine()\n");
- return status;
- }
- for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
- {
- DriverObject->MajorFunction[i] = CommonDispatch;
- }
- DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoctrlDispatch;
- DriverObject->DriverUnload = DriverUnload;
- return STATUS_SUCCESS;
- }
- VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
- {
- UNICODE_STRING ustrLinkName;
- PsSetCreateProcessNotifyRoutine(ProcessCreateMon, TRUE);
- RtlInitUnicodeString(&ustrLinkName, LINK_NAME);
- IoDeleteSymbolicLink(&ustrLinkName);
- IoDeleteDevice(DriverObject->DeviceObject);
- }
- //处理设备对象操作
- NTSTATUS CommonDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
- {
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = 0L;
- IoCompleteRequest( Irp, 0 );
- return Irp->IoStatus.Status;
- }
- NTSTATUS IoctrlDispatch(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
- {
- NTSTATUS ntStatus = STATUS_SUCCESS;
- PVOID pUserBuffer = NULL;
- ULONG ulInputSize = 0;
- ULONG ulOutputSize = 0;
- PIO_STACK_LOCATION pIrpStack = NULL;
- ULONG ulIoCtrlCode = 0;
- PProcMonData pProcMonData = NULL;
- PDEVICE_EXTENSION pDeviceExtension = NULL;
- pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
- pUserBuffer = pIrp->AssociatedIrp.SystemBuffer;
- pProcMonData = (PProcMonData)pUserBuffer;
- ulIoCtrlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
- ulInputSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
- ulOutputSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
- switch(ulIoCtrlCode)
- {
- case IOCTL_PROCWATCH:
- pDeviceExtension = (PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;
- pProcMonData->bCreate = pDeviceExtension->bCreate;
- pProcMonData->hParentId = pDeviceExtension->hParentId;
- pProcMonData->hProcessId = pDeviceExtension->hProcessId;
- break;
- default:
- ntStatus = STATUS_INVALID_PARAMETER;
- ulOutputSize = 0;
- break;
- }
- pIrp->IoStatus.Status = ntStatus;
- pIrp->IoStatus.Information = ulOutputSize;
- IoCompleteRequest(pIrp, IO_NO_INCREMENT);
- return ntStatus;
- }
- VOID ProcessCreateMon ( IN HANDLE hParentId, IN HANDLE PId,IN BOOLEAN bCreate )
- {
- // 获得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);
- }
注意了 上面这个工程中有个循环 ,循环中有个变量时test 这个变量在xp下 一般返回0 在win7 下返回0xffffffff;
这个代码没有改之前是
- while (::WaitForSingleObject(hProcessEvent, INFINITE))
- {
- ....
2.KSEMAPHORE
比如工作者与消费者之间 工作者增加一个资源 消费者才能买一个 消费者买了一个 就减少一个资源
用于同步与多个资源共享访问
- KSEMAPHORE kSemaphore;
- KeInitializeSemaphore(
- &kSemaphore,
- 1,//信号量的初始值
- 2 //信号量的最大值
- );
- LARGE_INTEGER waitTime = {0};
- waitTime.QuadPart = -1*10000000i64;
- KeWaitForSingleObject(&kSemaphore, Executive, KernelMode, FALSE, &waitTime);//0,立即返回;NULL,无限等待
- KeReleaseSemaphore(&kSemaphore ,IO_NO_INCREMENT , 1 , FALSE );
例子:工作者 与 消费者
- #include <ntddk.h>
- ULONG g_ulTotal = 0;
- KSEMAPHORE g_kSemaphore;
- VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
- {
- DbgPrint("Goodbye, driver\n");
- }
- VOID Worker(IN PVOID pContext)
- {
- ULONG i = 0;
- LARGE_INTEGER waitTime = {0};
- waitTime.QuadPart = -3*10000000i64;
- while(i < 10)
- {
- g_ulTotal++;
- KeReleaseSemaphore(&g_kSemaphore ,IO_NO_INCREMENT , 1 , FALSE );//增加一个资源semaphore
- DbgPrint("Worker:produced 1, total:%x\n", g_ulTotal);
- i++;
- KeDelayExecutionThread(KernelMode, FALSE, &waitTime);//延迟3秒
- }
- }
- VOID Consumer(IN PVOID pContext)
- {
- ULONG i = 10;
- LARGE_INTEGER waitTime = {0};
- waitTime.QuadPart = -3*10000000i64;
- while(i > 0)
- {
- KeWaitForSingleObject(&g_kSemaphore, Executive, KernelMode, FALSE, NULL);//等待资源并减少一个semaphore(等待成功后减少一个)
- g_ulTotal--;
- DbgPrint("Consumer:consumed 1, total:%x\n", g_ulTotal);
- i--;
- KeDelayExecutionThread(KernelMode, FALSE, &waitTime);//延迟3秒
- }
- }
- void StartThreads()
- {
- HANDLE hThread1 = NULL;
- HANDLE hThread2 = NULL;
- PVOID objtowait[2] = {NULL};
- NTSTATUS ntStatus =
- PsCreateSystemThread(//创建工作者线程
- &hThread1,
- 0,
- NULL,
- (HANDLE)0,
- NULL,
- Worker,
- NULL
- );
- if (!NT_SUCCESS(ntStatus))
- {
- return;
- }
- ntStatus =
- PsCreateSystemThread(//创建消费者线程
- &hThread2,
- 0,
- NULL,
- (HANDLE)0,
- NULL,
- Consumer,
- NULL
- );
- if (!NT_SUCCESS(ntStatus))
- {
- return;
- }
- if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
- {
- ntStatus = KfRaiseIrql(PASSIVE_LEVEL);
- }
- if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
- {
- return;
- }
- ntStatus = ObReferenceObjectByHandle(
- hThread1,
- THREAD_ALL_ACCESS,
- NULL,
- KernelMode,
- &objtowait[0],
- NULL
- );
- if (!NT_SUCCESS(ntStatus))
- {
- return;
- }
- ntStatus = ObReferenceObjectByHandle(
- hThread2,
- THREAD_ALL_ACCESS,
- NULL,
- KernelMode,
- &objtowait[1],
- NULL
- );
- if (!NT_SUCCESS(ntStatus))
- {
- ObDereferenceObject(objtowait[0]);
- return;
- }
- KeWaitForMultipleObjects(//等待两个线程结束
- 2,
- objtowait,
- WaitAll,
- Executive,
- KernelMode,
- FALSE,
- NULL,
- NULL);
- ObDereferenceObject(objtowait[0]);
- ObDereferenceObject(objtowait[1]);
- //KeWaitForSingleObject(objtowait,Executive,KernelMode,FALSE,NULL);
- return;
- }
- NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
- {
- pDriverObject->DriverUnload = DriverUnload;
- KeInitializeSemaphore(
- &g_kSemaphore,
- 0,//信号量的初始值
- 10 //信号量的最大值
- );
- StartThreads();
- return STATUS_SUCCESS;
- }
二.互斥
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
禁止访问分页内存
获得时间越短越好
使用方法:
//定义
- KIRQL OldIrql;
- KSPIN_LOCK mySpinLockProc;
- //获得
- KeAcquireSpinLock(
- &mySpinLockProc,
- &OldIrql);
- //对数据进行操作和访问
- ……
- //释放
- KeReleaseSpinLock(
- &mySpinLockProc,
- OldIrql);
2.ERESOURCE(读写共享锁)
- typedef struct _MY_LOCK
- {
- ERESOURCE m_Lock;//用于互斥
- }MY_LOCK;
- VOID __stdcall LockWrite(MY_LOCK* lpLock)
- {
- KeEnterCriticalRegion();
- ExAcquireResourceExclusiveLite(&lpLock->m_Lock, TRUE);
- }
- VOID __stdcall UnLockWrite(MY_LOCK* lpLock)
- {
- ExReleaseResourceLite(&lpLock->m_Lock);
- KeLeaveCriticalRegion();
- }
- VOID __stdcall LockRead(MY_LOCK* lpLock)
- {
- KeEnterCriticalRegion();
- ExAcquireResourceSharedLite(&lpLock->m_Lock, TRUE);
- }
- VOID __stdcall LockReadStarveWriter(MY_LOCK* lpLock)
- {
- KeEnterCriticalRegion();
- //读优先
- ExAcquireSharedStarveExclusive(&lpLock->m_Lock, TRUE);
- //写优先
- //ExAcquireSharedWaitForExclusive
- }
- VOID __stdcall UnLockRead(MY_LOCK* lpLock)
- {
- ExReleaseResourceLite(&lpLock->m_Lock);
- KeLeaveCriticalRegion();
- }
- VOID __stdcall InitLock(MY_LOCK* lpLock)
- {
- ExInitializeResourceLite(&lpLock->m_Lock);
- }
- VOID __stdcall DeleteLock(MY_LOCK* lpLock)
- {
- ExDeleteResourceLite(&lpLock->m_Lock);
- }
- //ERESOURCE的使用
- LIST_ENTRY g_WaitList;
- MY_LOCK g_WaitListLock;
- //DriverEntry里
- InitLock(&g_WaitListLock);
- //多线程环境里
- LockWrite(&g_WaitListLock);
- lpWaitEntry = LookupWaitEntryByID(&g_WaitList, lpReply->m_ulWaitID);
- if (lpWaitEntry != NULL)
- {
- lpWaitEntry->m_bBlocked = lpReply->m_ulBlocked;
- KeSetEvent(&lpWaitEntry->m_ulWaitEvent, 0, FALSE);
- return;
- }
- UnLockWrite(&g_WaitListLock);
- //DriverUnload里
- DeleteLock(&g_WaitListLock);
3.FAST_MUTEX
用于互斥
大于APC_LEVEL就不能使用了(PL AL可用)
不能递归获得锁
- FAST_MUTEX gSfilterAttachLock
- ExInitializeFastMutex( &gSfilterAttachLock );
- ExAcquireFastMutex( &gSfilterAttachLock );
- ExAcquireFastMutex( &gSfilterAttachLock );//错 递归获得锁
- //Do something here
- ……
- ExReleaseFastMutex( &gSfilterAttachLock );
- ExReleaseFastMutex( &gSfilterAttachLock );
例子:
- #include <ntddk.h>
- ULONG g_ulTotal = 0;
- FAST_MUTEX g_fmLock;
- VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
- {
- DbgPrint("Goodbye, driver\n");
- }
- VOID ThreadProc1(IN PVOID pContext)
- {
- ULONG i = 0;
- ExAcquireFastMutex(&g_fmLock);
- g_ulTotal++;
- DbgPrint("ThreadProc1:%x\n", g_ulTotal);
- ExReleaseFastMutex(&g_fmLock);
- }
- VOID ThreadProc2(IN PVOID pContext)
- {
- ULONG i = 0;
- ExAcquireFastMutex(&g_fmLock);
- g_ulTotal++;
- DbgPrint("ThreadProc2:%x\n", g_ulTotal);
- ExReleaseFastMutex(&g_fmLock);
- }
- void StartThreads()
- {
- HANDLE hThread1 = NULL;
- HANDLE hThread2 = NULL;
- PVOID objtowait[2] = {NULL};
- NTSTATUS ntStatus =
- PsCreateSystemThread(
- &hThread1,
- 0,
- NULL,
- (HANDLE)0,
- NULL,
- ThreadProc1,
- NULL
- );
- if (!NT_SUCCESS(ntStatus))
- {
- return;
- }
- ntStatus =
- PsCreateSystemThread(
- &hThread2,
- 0,
- NULL,
- (HANDLE)0,
- NULL,
- ThreadProc2,
- NULL
- );
- if (!NT_SUCCESS(ntStatus))
- {
- return;
- }
- if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
- {
- ntStatus = KfRaiseIrql(PASSIVE_LEVEL);
- }
- if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
- {
- return;
- }
- ntStatus = ObReferenceObjectByHandle(
- hThread1,
- THREAD_ALL_ACCESS,
- NULL,
- KernelMode,
- &objtowait[0],
- NULL
- );
- if (!NT_SUCCESS(ntStatus))
- {
- return;
- }
- ntStatus = ObReferenceObjectByHandle(
- hThread1,
- THREAD_ALL_ACCESS,
- NULL,
- KernelMode,
- &objtowait[1],
- NULL
- );
- if (!NT_SUCCESS(ntStatus))
- {
- ObDereferenceObject(objtowait[0]);
- return;
- }
- KeWaitForMultipleObjects(
- 2,
- objtowait,
- WaitAll,
- Executive,
- KernelMode,
- FALSE,
- NULL,
- NULL);
- ObDereferenceObject(objtowait[0]);
- ObDereferenceObject(objtowait[1]);
- //KeWaitForSingleObject(objtowait,Executive,KernelMode,FALSE,NULL);
- return;
- }
- NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
- {
- pDriverObject->DriverUnload = DriverUnload;
- ExInitializeFastMutex(&g_fmLock);
- StartThreads();
- return STATUS_SUCCESS;
- }
4.KMUTEX
基本淘汰,使用FAST_MUTEX取代
特点:
FAST_MUTEX无法递归,KMUTEX可以
FAST_MUTEX无法WAIT,KMUTEX可以
FAST_MUTEX 在APC LEVE,KMUTEX任意LEVEL
用法:
- KMUTEX mutex;
- KeInitializeMutex(
- & mutex,
- 0
- );
- KeWaitForSingleObject(& mutex, Executive, KernelMode, FALSE, &MmOneSecond);
- 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多线程演示:
- ULONG WINAPI ThreadProc(void* arg)
- {
- return 1;
- }
- VOID CreateThread()
- {
- HANDLE hThread = NULL;
- hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
- WaitForSingleObject(hThread, INFINITE);
- CloseHandle(hThread);
- hThread = NULL;
- }
- UINT WINAPI ThreadProc(LPVOID lpParameter)
- {
- return 0;
- }
- VOID Beginthreadex()
- {
- unsigned tid = 0;
- HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0, ThreadProc, NULL, 0, &tid);
- WaitForSingleObject( hThread, INFINITE );
- CloseHandle(hThread);
- hThread = NULL;
- }
- UINT threadProc(LPVOID v)
- {
- AfxEndThread(0);
- }
- VOID AfxbeginThread()
- {
- CWinThread *pThreadR = AfxBeginThread(threadProc,(LPVOID)param);
- pThreadR->SuspendThread();
- pThreadR->m_bAutoDelete = FALSE;
- pThreadR->ResumeThread();
- if (WaitForSingleObject(pThreadR->m_hThread, 2*1000)==WAIT_TIMEOUT)
- {
- TerminateThread(pThreadR->m_hThread, 0);
- }
- delete (pThreadR);
- pThreadR = NULL;
- }
三个函数的区别
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中不能用。所以任何时候最好都不要用。
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
- class CLock
- {
- public:
- void Lock() {EnterCriticalSection(&m_sec);}
- void Unlock() {LeaveCriticalSection(&m_sec);}
- CLock () {InitializeCriticalSection(&m_sec);}
- ~ CLock () {DeleteCriticalSection(&m_sec);}
- private:
- CRITICAL_SECTION m_sec;
- };
- class CAutoLock
- {
- public:
- CAutoLock(CLock * lpLock) :
- m_pLock (lpLock)
- {
- m_pLock ->Lock();
- }
- ~CAutoLock()
- {
- m_pLock ->Unlock();
- }
- private:
- CLock * m_pLock;
- };
使用例子:
- {
- CLock m_lock;
- CAutoLock(&m_lock);
- ….
- }