互斥体(用户模式 内核模式 快速互斥体)
一.用户模式互斥体
创建互斥体:
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // pointer to security attributes
BOOL bInitialOwner, //始化时是否被占有
LPCTSTR lpName // pointer to mutex-object name
);
释放互斥体:
BOOL ReleaseMutex(
HANDLE hMutex // handle to mutex object
);
代码内容:获得了互斥体之后,同一个线程中可以递归获得互斥体,就是得到互斥体的线程还可以再次获得这个互斥体,或者说互斥体对于已经获得互斥体的线程不产生”互斥”关系。
// Mutex-ThreadSynchronization.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <windows.h> #include <iostream> using namespace std; //获得互斥体的线程不产生"互斥"关系(不互斥自己) DWORD WINAPI ThreadProcedure(LPVOID ParameterData); int main() { HANDLE ThreadHandle[2] = {0}; int i; HANDLE MutexHandle = CreateMutex( NULL, FALSE, //表明初始化时是否被占有 NULL); if (MutexHandle == NULL) { printf("CreateMutex() Error\r\n"); goto Exit; } for (i = 0; i < 2; i++) { ThreadHandle[i] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProcedure, (PVOID)&MutexHandle, 0, NULL); if (ThreadHandle[i] == NULL) { printf("CreateThread() Error\r\n"); goto Exit; } } WaitForMultipleObjects(2, ThreadHandle, TRUE, INFINITE); for (i = 0; i < 2; i++) CloseHandle(ThreadHandle[i]); Exit: { if (MutexHandle!=NULL) { CloseHandle(MutexHandle); MutexHandle = NULL; } } return 0; } DWORD WINAPI ThreadProcedure(LPVOID ParameterData) { HANDLE MutexHandle = *((HANDLE*)ParameterData); DWORD Looping = 0; BOOL IsOk = 0; //占有几次就必须解锁几次 while (Looping < 5) { //占有互斥体 IsOk = WaitForSingleObject( MutexHandle, INFINITE); IsOk -= WAIT_OBJECT_0; switch (IsOk) { case WAIT_OBJECT_0: //等待的对象变为已通知状态,那么返回值是WAIT_OBJECT_0。 { __try { printf("ThreadID:%d\r\n", GetCurrentThreadId()); Looping++; } __finally { //释放互斥体 if (!ReleaseMutex(MutexHandle)) { } } break; } case WAIT_ABANDONED: return FALSE; } } printf("ThreadProcedure() Exit\r\n"); return TRUE; }
二.内核模式互斥体
1.互斥体在内核模式下的结构体为KMUTEX,使用前需要进行初始化:KeInitializeMutex,释放互斥体使用KeReleaseMutex内核函数
2.PsCreateSystemThread创建新的线程占用互斥体
3.ObReferenceObjectByHandle将句柄转化为指向object的指针,交给 KeWaitForMultipleObjects函数,用于同时等待一个或多个同步对象。
NTKERNELAPI
NTSTATUS
KeWaitForMultipleObjects (
_In_ ULONG Count, //数组中指针的个数
_In_reads_(Count) PVOID Object[], //指向一个指针数组
_In_ _Strict_type_match_ WAIT_TYPE WaitType, //等待所有对象都进入信号态
_In_ _Strict_type_match_ KWAIT_REASON WaitReason,
_In_ __drv_strictType(KPROCESSOR_MODE/enum _MODE,__drv_typeConst) KPROCESSOR_MODE WaitMode,
_In_ BOOLEAN Alertable,
_In_opt_ PLARGE_INTEGER Timeout,
_Out_opt_ PKWAIT_BLOCK WaitBlockArray
);
#include <ntifs.h> VOID SeCreateMutex(); VOID ThreadProcedure(PVOID ParameterData); VOID DriverUnload(PDRIVER_OBJECT DriverObject); NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath) { NTSTATUS Status = STATUS_SUCCESS; PDEVICE_OBJECT DeviceObject = NULL; DriverObject->DriverUnload = DriverUnload; SeCreateMutex(); return Status; } VOID DriverUnload(PDRIVER_OBJECT DriverObject) { DbgPrint("DriverUnload()\r\n"); } VOID SeCreateMutex() { KMUTEX Mutex; HANDLE ThreadHandle[2] = { 0 }; ULONG i = 0; PVOID ThreadObject[2] = { 0 }; KeInitializeMutant(&Mutex, 0); for (i = 0; i < 2; i++) { PsCreateSystemThread(&ThreadHandle[i], 0, NULL, NULL, NULL, ThreadProcedure, &Mutex); } for (i = 0; i < 2; i++) { //把线程句柄转换为可以等待的指针 ObReferenceObjectByHandle(ThreadHandle[i], 0, NULL, KernelMode, &ThreadObject[i], NULL); } //等待2个新建线程执行完毕 KeWaitForMultipleObjects( 2, //数组中指针的个数 ThreadObject, //指向一个指针数组 WaitAll, //等待所有对象都进入信号态 Executive, KernelMode, FALSE, NULL, NULL); for (i = 0; i < 2; i++) { ObDereferenceObject(ThreadObject[i]); ZwClose(ThreadHandle[i]); ThreadHandle[i] = NULL; } } VOID ThreadProcedure(PVOID ParameterData) { PKMUTEX Mutex = (PKMUTEX)ParameterData; int i = 0; //占有几次解锁几次 for (i=0;i<3;i++) { KeWaitForSingleObject(Mutex, Executive, KernelMode, FALSE, NULL); //该函数是以微秒为单位 KeStallExecutionProcessor(10000); //0.01秒 DbgPrint("ThreadID:%d\r\n",PsGetCurrentThreadId()); KeReleaseMutex(Mutex, FALSE); } PsTerminateSystemThread(STATUS_SUCCESS); //当线程退出Mutex就不起作用了即使不解占有 }
三.快速互斥体
快速互斥体是DDK提供的另外一种内核同步对象,他的特征类似于前面介绍的普通互斥体。他们两的作用完全一样,之所以被称为是快速互斥体,是因为它执行的速度比普通的互斥体速度快(这里指的是获取和释放的速度)。然而,快速互斥体对象不能被递归获取。
普通互斥体在内核中用KMUTEX数据结构表示,而快速互斥体在内核中用FAST_MUTEX数据结构描述。
除此之外,对快速互斥体的初始化,获取和释放对应的内核函数也和普通互斥体不同。
初始化:
VOID
ExInitializeFastMutex(
IN PFAST_MUTEX FastMutex
);
获取:
VOID
ExAcquireFastMutex(
IN PFAST_MUTEX FastMutex
);
释放:
VOID
ExReleaseFastMutex(
IN PFAST_MUTEX FastMutex
);
#include <ntifs.h> VOID SeCreateFastMutex(); VOID ThreadProcedure(PVOID ParameterData); VOID DriverUnload(PDRIVER_OBJECT DriverObject); NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath) { NTSTATUS Status = STATUS_SUCCESS; PDEVICE_OBJECT DeviceObject = NULL; DriverObject->DriverUnload = DriverUnload; SeCreateFastMutex(); return Status; } VOID DriverUnload(PDRIVER_OBJECT DriverObject) { DbgPrint("DriverUnload()\r\n"); } VOID SeCreateFastMutex() { HANDLE ThreadHandle[2] = { 0 }; FAST_MUTEX Mutex; ULONG i = 0; PVOID ThreadObject[2] = { 0 }; ExInitializeFastMutex(&Mutex); for (i = 0; i < 2; i++) { PsCreateSystemThread(&ThreadHandle[i], 0, NULL, NULL, NULL, ThreadProcedure, &Mutex); } for (i = 0; i < 2; i++) { ObReferenceObjectByHandle(ThreadHandle[i], 0, NULL, KernelMode, &ThreadObject[i], NULL); } KeWaitForMultipleObjects(2, ThreadObject, WaitAll, Executive, KernelMode, FALSE, NULL, NULL); for (i = 0; i < 2; i++) { ObDereferenceObject(ThreadObject[i]); ZwClose(ThreadHandle[i]); ThreadHandle[i] = NULL; } } VOID ThreadProcedure(PVOID ParameterData) { PFAST_MUTEX Mutex = (PFAST_MUTEX)ParameterData;; int i = 0; for (i = 0; i < 3; i++) { ExAcquireFastMutex(Mutex); //该函数是以微秒为单位 KeStallExecutionProcessor(10000); //0.01秒 DbgPrint("ThreadID:%d\r\n", PsGetCurrentThreadId()); ExReleaseFastMutex(Mutex); //如果当前线程不解锁就互斥住自己 } PsTerminateSystemThread(STATUS_SUCCESS); }