互斥体(用户模式 内核模式 快速互斥体)
一.用户模式互斥体
创建互斥体:
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
);
代码内容:获得了互斥体之后,同一个线程中可以递归获得互斥体,就是得到互斥体的线程还可以再次获得这个互斥体,或者说互斥体对于已经获得互斥体的线程不产生”互斥”关系。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | // 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
);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | #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
);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #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); } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗