磁力驱动泵浦-上海龙亚泵业与您共同探讨磁力驱动泵的性能参数、价格行情!
  • 磁力驱动泵
  • 磁力驱动泵
当前位置: 主页 > 氟塑料磁力驱动泵 >

氟塑料磁力驱动泵上海厂家Delphi驱动开发研究之内核同步对象

时间:2011-12-22 23:51来源:龙亚磁力驱动泵 作者:上海龙亚磁力驱动泵 点击:
>在上篇教程中,我们解说了内核同步对象中的计时器对象的使用方法,有关同步的另一个常见的用处就是对数据的独占访问。>>在本教程中,我们将同时开始工作多个线程,所有这些线程都会数次对一个ULONG类型的共享变量进行累加操作,最终这个共享变量的值
>在上篇教程中,我们解说了内核同步对象中的计时器对象的使用方法,有关同步的另一个常见的用处就是对数据的独占访问。>>在本教程中,我们将同时开始工作多个线程,所有这些线程都会数次对一个ULONG类型的共享变量进行累加操作,最终这个共享变量的值将会等于所有线程工作次数的全体。>>这个共享变量可以是任意类型的数据,比如我们拦截到的系统服务(这些将在后面的教程里讨论)的相关统计数据。如果没有同步机制,这些共享数据的成果就无法预知了,我们可能患上不到不错的统计数据甚或紧张的话可能会导致系统崩溃。>>处理完成上述问题最好的方案就是使用互斥(Mutex) 对象了,在内核中,Mutex又被称为突变体(mutants)。 互斥,顾名思义,就是排它性访问,也就是同一时间内只允许一个线程访问共享数据,同一驱动的所有线程共同拥有一个Mutex对象,如果一个线程要访问共享变量,它首先要获取这个Mutex对象,一旦某个线程取患上了Mutex对象,就可以对共享变量进行存取操作,否则就只能等待直到其他线程释放Mutex对象。经由过程Mutex机制就能确保同一时间只能有一个线程访问共享变量。>>11.1教程源码:>>unit MutualExclusion;>>{$POINTERMATH ON}>>interface>>uses>>nt_status, ntoskrnl, fcall;>>function _DriverEntry(pDriverObject:PDRIVER_OBJECT;>>pusRegistryPath:PUNICODE_STRING): NTSTATUS; stdcall;>>implentation>>const>>{ 不能超过MAXIMUM_WAIT_OBJECTS (64) - 最大等待对象数 }>>NUM_THREADS = 5;>>NUM_WORKS= 10;>>var>>g_usDeviceName, g_usSymbolicLinkName: UNICODE_STRING;>>g_pkWaitBlock: PKWAIT_BLOCK;>>{ PKTHREAD数组 }>>g_apkThreads: array[0..NUM_THREADS - 1] of PVOID;>>g_dwCountThreads: DWORD;>>g_kMutex: KMUTEX;>>g_dwWorkElent: DWORD;>>function ThreadProc: NTSTATUS; stdcall;>>var>>liDelayTime:LARGE_INTEGER;>>pkThread: PVOID;{ PKTHREAD }>>dwWorkElent: ULONG;>>dwCount, dwTmp: ULONG;>>begin>>pkThread := PsGetCurrentThread;>>DbgPrint('MutualExclusion: Thread %08X is entering ThreadProc'#13#10, pkThread);>>dwCount := 0;>>while dwCountnil then>>begin>>ExFreePool(g_pkWaitBlock);>>g_pkWaitBlock := nil;>>end;>>end;>>procedure DriverUnload(pDriverObject:PDRIVER_OBJECT); stdcall;>>begin>>DbgPrint('MutualExclusion: Entering DriverUnload'#13#10);>>DbgPrint('MutualExclusion: Wait for threads exit...'#13#10);>>{ 因为ThreadProc存在于我们的驱动主体中,因此只要还有一个>>{ 线程在运行,就不能卸载驱动,必必要等到所有的线程都退出 }>>if g_dwCountThreads > 0 then>>begin>>{ 没有配置超时时间,一直等待到所有线程退出 }>>{ 因为有多个线程对象,所以使用KeWaitForMultipleObjects }>>KeWaitForMultipleObjects(g_dwCountThreads, @g_apkThreads,>>WaitAll, Executive, KernelMode,>>False, nil, g_pkWaitBlock);>>{ 执行到这里时,所有线程均已退出,就可以释放所有线程对象了 }>>while g_dwCountThreads > 0 do>>begin>>Dec(g_dwCountThreads);>>ObfDereferenceObject(g_apkThreads[g_dwCountThreads]);>>end;>>end;>>CleanUp(pDriverObject);>>{ 打印成果. 这里g_dwWorkElent的值应该等于NUM_THREADS * NUM_WORKS }>>DbgPrint('MutualExclusion: WorkElent = %d'#13#10, g_dwWorkElent);>>DbgPrint('MutualExclusion: Leaving DriverUnload'#13#10);>>end;>>function StartThreads: NTSTATUS;>>var>>hThread:HANDLE;>>i, dwCount:ULONG;>>rtnCode: NTSTATUS;>>begin>>i := 0;>>{ dwCount保存实际运行的线程数 }>>dwCount := 0;>>while i0 then>>begin>>Result := STATUS_SUCCESS; { 返回成功说明至少有一个线程在运行 }>>end else>>begin>>Result := STATUS_UNSUCCESSFUL; { 无法开始工作任何线程 }>>end;>>end;>>function _DriverEntry(pDriverObject:PDRIVER_OBJECT;>>pusRegistryPath:PUNICODE_STRING): NTSTATUS; stdcall;>>var>>status:NTSTATUS;>>pDeviceObject:PDEVICE_OBJECT;>>liTickCount:LARGE_INTEGER;>>begin>>status := STATUS_DEVICE_CONFIGURATION_ERROR;>>RtlInitUnicodeString(@g_usDeviceName, '\Device\MutualExclusion');>>RtlInitUnicodeString(@g_usSymbolicLinkName, '\DosDevices\MutualExclusion');>>if IoCreateDevice(pDriverObject, 0, @g_usDeviceName,>>FILE_DEVICE_UNKNOWN, 0, False,>>@pDeviceObject) = STATUS_SUCCESS then>>begin>>if IoCreateSymbolicLink(@g_usSymbolicLinkName,>>@g_usDeviceName) = STATUS_SUCCESS then>>begin>>{ 因为ThreadProc存在于我们的驱动主体中,因此只要还有一个>>{ 线程在运行,就不能卸载驱动,必必要等到所有的线程都退出>>{ 方可卸载驱动。为了达到这个目的,我们需要一些内存。必须>>{ 在这里分配这些内存,因为如果我们在DriverUnload中去分配,>>{ 一旦分配掉败,就无法停止驱动了。}>>{ 每个线程对象都有一个内建的等待块(wait block)数组(缺省一>>{ 个数组中有3个等待块)用于有几个对象并存时的等待操作。由于>>{ 没有额外的等待块可供使用,因此通常环境下,这些内建的等待>>{ 块数组被用于多个等待操作。当然,如果需要并存的对象的数目>>{ 超过了内建等待块的数目, 可以经由过程配置WaitBlockArray参数指>>{ 定一个替代的等待块用于等待操作。}>>{ 在本例中,我们的NUM_THREADS大于THREAD_WAIT_OBJECTS(3). }>>{ 因此就必必要使用自己的Wait Block了. }>>g_pkWaitBlock := ExAllocatePool(NonPagedPool, NUM_THREADS * SizeOf(KWAIT_BLOCK));>>if g_pkWaitBlock>>11.2 DriverEntry>>g_pkWaitBlock := ExAllocatePool(NonPagedPool, NUM_THREADS * SizeOf(KWAIT_BLOCK));>>分配NUM_THREADS * SizeOf(KWAIT_BLOCK)大小的内存,恒量NUM_THREADS决议我们一共开始工作多少个线程。分配的内存块指针保存在整个的局面:胸怀~变量g_pkWaitBlock中,我们将在卸载驱动时使用这块内存,为什么需要分配这块内存以及为什么要在驱动初始化时分配这块内存的原因稍后再做诠释,在这里我们并不使用这块内存。>>KeInitializutex(@g_kMutex, 0);>>这里我们将使用Mutex对象来同步,所以首先要调用KeInitializutex函数来初始化Mutex,KeInitializutex函数只是简单的填充一个KMUTANT变量,KMUTANT结构描述一个Mutex对象,定义如次:>>KMUTANT = packed record>>Header:TDispatcherHeader;>>MutantListEntry:TListEntry;>>OwnerThread:PKThread;>>Abandoned:Boolean;>>ApcDisable:Byte;>>Alignment0:Word;>>end;>>初始化完成后,Mutex处于自由状况可供使用了。>>KeQueryTickCount(@liTickCount);>>为了最大程度地模拟真实环境,需要让各个线程乱序访问共享资源,为了达到这个目的,我们将生成一些RAND数,并使用这些RAND数来控制每个线程的延迟时间间隔。Ntoskrnl.exe导出了标准库函数rand,这个函数产生0--$7FFF之间的一个整数。产生RAND数需要一个种子数(有些地方称之为主数),在内核中,这个种子数是一个整个的局面:胸怀~变量,在系统引导后就被初始化并且始终存在于内存中了,所以我们可以不消调用srand去初始化RAND数发生器的种子的,不过我们的程序照旧依照常规调用了srand函数去初始化RAND数发生器种子,首先我们调用KeQueryTickCount函数返回自系统开始工作以来发生过的计时器中断的次数,并以这个数为参数调用srand初始化RAND数发生器种子。>>g_dwWorkElent := 0;>>g_dwWorkElent就是本例中所有线程的共享资源。>>11.3 创建线程>>i := 0;>>{ dwCount保存实际运行的线程数 }>>dwCount := 0;>>while i>>这里创建线程的方法与我们在TimerWorker里的方法没有什么大的不同,我们经由过程循环调用PsCreateSystThread创建了NUM_THREADS个线程,并将指向线程的指针保存在g_apkThreads数组中,实际创建的线程数保存在g_dwCountThreads变量中,线程函数依旧是ThreadProc。这里唯一要注意的就是创建的线程数不能大于MAXIMUM_WAIT_OBJECTS,MAXIMUM_WAIT_OBJECTS是一个恒量,其值等于64,也就是说,同一时间并存的线程数不能超过6四个。在DriverUnload里,我们将等待所有这些创建的线程正常退出后再卸载驱动。>>11.4 线程函数ThreadProc>>我们创建了NUM_THREADS个线程,这些线程的线程函数最终都会获患上执行的权限,其ThreadProc函数将会执行。>>pkThread := PsGetCurrentThread;>>DbgPrint('MutualExclusion: Thread %08X is entering ThreadProc'#13#10, pkThread);>>函数PsGetCurrentThread返回一个当前线程结构的指针,我们用DbgPrint输出该指针的地址。>>dwCount := 0;>>while dwCount>>主循环重复执行NUM_WORKS次,每次循环都会累加共享资源--整个的局面:胸怀~变量g_dwWorkElent,每个线程累加NUM_WORK次。>>首先调用KeWaitForMutexObject竞争 Mutex,一旦取患上Mutex,线程开始运行,并可以自由的操作共享资源,剩下NUM_THREADS-1个线程将处于等待状况,直到这个线程释放Mutex。>>为了模拟线程对共享资源的访问,我们简单地RAND停止线程执行0—50毫秒。>>liDelayTime.HighPart := liDelayTime.HighPart or -1;>>liDelayTime.LowPart := -(rand shl 4);>>KeDelayExecutionThread(KernelMode, false, @liDelayTime);>>函数rand产生一个0--$7FFF之间的RAND数,再乘以16就是我们想要的延迟值。KeDelayExecutionThread和KeSetTimerEx都传递一个64位的延迟值去配置延迟参数,不同之处在于KeSetTimerEx传递的是一个LARGE_INTEGER,而KeDelayExecutionThread传递的是一个指向LARGE_INTEGER的指针。KeDelayExecutionThread的作用是将当前线程置于可报警或者不可报警的等待状况给定的时间,此函数必须执行在IRQL = PASSIVE_LEVEL,内部是经由过程计时器实现的。>>Inc(dwWorkElent);>>g_dwWorkElent := dwWorkElent;>>转变共享资源的值并写回。>>KeReleasutex(@g_kMutex, False);>>工作完成,我们必须释放Mutex以便其他正在等待的线程捕获它并完成自己的工作。KeReleasutex的函数原型如次:>>function KeReleasutex(Mutex:PKMutex; Wait:LongBool):LONG; stdcall;>>其作用是释放一个由KeWaitXXX函数占用的Mutex对象,此函数可临时晋升IRQL。当参数Wait=false时,函数返回前会把IRQL恢复到调用它之前的原始值;如果Wait=true,函数返回时不会降低IRQL,在这种环境下,KeReleasutex调用必须跟随在一个KeWaitXXX函数调用之后。如果配置Wait=TRUE,调用者可以阻止在KeWaitXXX调用和KeReleasutex调用之间不必要的上下文切换。KeWaitXXX函数在返回前,会把IRQL恢复到开始KeReleasutex调用之前的值,只管IRQL不允许在两个函数调用之间进行上下文切换,但是这些调用在用于开始和竣事一个原子操作时并非很可靠。比如在这两个函数调用之间,同时在另一个措置惩罚器上运行的线程可能会转变事件对象或者等待的目的对象的状况。如果调用者正运行在IRQL=DISPATCH_LEVEL或正位于一个任意的线程上下文中,传递给KeWaitXXX函数的Timeout参数必须为0。>>Result := PsTerminateSystThread(STATUS_SUCCESS);>>竣事本线程,让其他线程执行。如果所有线程都执行完毕则毁掉线程对象。>>11.5 DriverUnload>>与TimerWorks驱动类似,我们必必要等待所有线程竣事方可卸载驱动,因为所有线程都位于驱动主体中,如果我们在不合适的时候卸载驱动可能导致系统崩溃。处理完成方法就是等待所有的线程竣事。>>if g_dwCountThreads > 0 then>>begin>>{ 没有配置超时时间,一直等待到所有线程退出 }>>{ 因为有多个线程对象,所以使用KeWaitForMultipleObjects }>>KeWaitForMultipleObjects(g_dwCountThreads, @g_apkThreads,>>WaitAll, Executive, KernelMode,>>False, nil, g_pkWaitBlock);>>因为有多个线程,所以我在要调用KeWaitForMultipleObjects而不是KeWaitForSingleObject。KeWaitForMultipleObjects的第一个参数指定要等待对象的数量,也就是第二个参数传送的对象指针数组的个数,第三个参数决议是不是所有的对象或者任意一个对象在需要满足等待条件前必须达到信号态,如果取值为WaitAny,KeWaitForMultipleObjects会返回STATUS_WAIT_0到STATUS_WAIT_63,如果对象指针数组的第一个对象被置为信号态,则返回STATUS_WAIT_0,第二个则返回STATUS_WAIT_1,依此类推,返回值的低6位则是对象在对象指针数组中的下标,下标从0开始。最后一个参数是一个指向KWAIT_BLOCK结构的指针,如果参数一小于等于THREAD_WAIT_OBJECTS,此参数可以置为nil,否则,此参数必须指向一个NUM_THREADS * SizeOf(KWAIT_BLOCK)大小的KWAIT_BLOCK结构数组。我们的程序里线程数大于THREAD_WAIT_OBJECTS,因此我们就无法使用线程内建的等待块,必必要创建自己的等待块。>>while g_dwCountThreads > 0 do>>begin>>Dec(g_dwCountThreads);>>ObfDereferenceObject(g_apkThreads[g_dwCountThreads]);>>end;>>这段代码毁掉我们创建的线程对象。>>DbgPrint('MutualExclusion: WorkElent = %d'#13#10, g_dwWorkElent);>>DbgPrint输出g_dwWorkElent的值,这个值应该等于NUM_THREADS * NUM_WORKS。>尊敬的用户您好:上海氟塑料磁力驱动泵厂家,请找上海龙亚氟塑料磁力驱动泵厂,如需选型报价的客户请致电O21-6l557088 或 O21-6l557088 (*^__^*) 嘻嘻……。 (责任编辑:龙亚磁力驱动泵厂)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
友情链接

男性增大

傲博胶囊

崔情水

崔情

崔情香水女用药