互斥体(用户模式 内核模式 快速互斥体)
一.用户模式互斥体
创建互斥体:
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);
}
浙公网安备 33010602011771号