管理博文 win10驱动开发18——用户/内核模式的线程同步

自旋锁

#include <ntddk.h>   
#include <windef.h>

VOID Unload(IN PDRIVER_OBJECT pDriverObject)
{
	KdPrint(("Goodbye driver\n"));
}

VOID SpinLockTest() 
{
	//在初始化自旋锁的时候会初始化PASSIVE_LEVEL
	KSPIN_LOCK SpinLock;
	KIRQL irql;
	KeInitializeSpinLock(&SpinLock);
	switch (KeGetCurrentIrql())
	{
	case DISPATCH_LEVEL:
		KdPrint(("DISPATCH_LEVEL\n"));
		break;
	case APC_LEVEL:
		KdPrint(("APC_LEVEL\n"));
		break;
	case PASSIVE_LEVEL:
		KdPrint(("PASSIVE_LEVEL\n"));
		break;
	default:
		break;
	}
	KeAcquireSpinLock(&SpinLock, &irql);
	//在获取自旋锁的时候irql会提升到DISPATCH_LEVEL
	switch (KeGetCurrentIrql())
	{
	case DISPATCH_LEVEL:
		KdPrint(("DISPATCH_LEVEL\n"));
		break;
	case APC_LEVEL:
		KdPrint(("APC_LEVEL\n"));
		break;
	case PASSIVE_LEVEL:
		KdPrint(("PASSIVE_LEVEL\n"));
		break;
	default:
		break;
	}
	//在释放自旋锁之后会恢复到PASSIVE_LEVEL
	KeReleaseSpinLock(&SpinLock, irql);
	switch (KeGetCurrentIrql())
	{
	case DISPATCH_LEVEL:
		KdPrint(("DISPATCH_LEVEL\n"));
		break;
	case APC_LEVEL:
		KdPrint(("APC_LEVEL\n"));
		break;
	case PASSIVE_LEVEL:
		KdPrint(("PASSIVE_LEVEL\n"));
		break;
	default:
		break;
	}
}

extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
	KdPrint(("Hello driver\n"));
	DriverObject->DriverUnload = Unload;
	SpinLockTest();
	return STATUS_SUCCESS;
}

在这里插入图片描述

用户模式下的同步对象

用户模式下的事件

对象描述
Event(事件)阻塞一个线程直到其他线程检测到某事件发生
Semaphore(信号灯)与事件对象相似,但可以满足任意数量的等待
Mutex(互斥)执行到关键代码段时,禁止其他线程执行该代码段
Thread(线程)阻塞一个线程直到另一个线程结束
#include <windows.h>
#include <stdio.h>

DWORD WINAPI Threadproc(PVOID Context)
{
	//首先创建一个事件,得到事件句柄
	PHANDLE phEvent = (PHANDLE)Context;
	printf("进入到线程函数里\n");
	SetEvent(*phEvent);
	printf("线程函数结束\n");
	return 0;
}

int main()
{
	HANDLE hEvent= CreateEvent(NULL, FALSE, FALSE, NULL);
	if (NULL==hEvent)
	{
		printf("创建事件失败%d\n", GetLastError());
		return -1;
	}
	//事件句柄传给线程函数,
	CreateThread(NULL, 0, Threadproc, &hEvent, 0, NULL);
	//设置有信号状态,此时这个等待就会结束
	WaitForSingleObject(hEvent, INFINITE);
	printf("进程结束");
	return 0;
}

在这里插入图片描述

用户模式下的信号灯

#include <windows.h>
#include <stdio.h>

DWORD WINAPI Threadproc(PVOID Context)
{
	//首先创建一个事件,得到事件句柄
	PHANDLE phSemaphore = (PHANDLE)Context;
	printf("进入到线程函数\n");
	Sleep(5000);
	ReleaseSemaphore(*phSemaphore, 1, NULL);
	printf("线程函数结束\n");
	return 0;
}

int main()
{
	//设置两个信号
	HANDLE hSemaphore = CreateSemaphore(NULL, 2, 2, NULL);
	if (NULL == hSemaphore)
	{
		printf("信号量创建失败%d\n", GetLastError());
		return -1;
	}
	//设置有信号状态,此时这个等待就会结束
	WaitForSingleObject(hSemaphore, INFINITE);
	WaitForSingleObject(hSemaphore, INFINITE);
	//设置两个信号,当出现第三个信号,如果前面没有释放将会卡住,把下面一行注释掉将会卡住
	//Threadproc里面5秒后释放了一个信号所以5秒后可以输出主线程
	CreateThread(NULL, 0, Threadproc,&hSemaphore,0,NULL);
	WaitForSingleObject(hSemaphore, INFINITE);
	printf("主线程结束");
	return 0;
}

在这里插入图片描述

用户模式下的互斥器

#include <windows.h>
#include <stdio.h>

DWORD WINAPI Threadproc1(PVOID Context)
{
	//首先创建一个事件,得到事件句柄
	PHANDLE phMutex = (PHANDLE)Context;
	WaitForSingleObject(*phMutex, INFINITE);
	printf("进入到线程1\n");
	Sleep(2000);
	printf("线程函数结束1\n");
	ReleaseMutex(*phMutex);
	return 0;
}

DWORD WINAPI Threadproc2(PVOID Context)
{
	//首先创建一个事件,得到事件句柄
	PHANDLE phMutex = (PHANDLE)Context;
	WaitForSingleObject(*phMutex, INFINITE);
	printf("进入到线程2\n");
	Sleep(2000);
	printf("线程函数结束2\n");
	ReleaseMutex(*phMutex);
	return 0;
}

int main()
{
	//创建事件
	HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);
	if (NULL == hMutex)
	{
		printf("创建互斥事件失败%d\n", GetLastError());
		return -1;
	}
	HANDLE hThread[2] = { NULL };
	hThread[0] =CreateThread(NULL, 0, Threadproc1, &hMutex, 0, NULL);
	hThread[1] =CreateThread(NULL, 0, Threadproc2, &hMutex, 0, NULL);
	//参数1:数组个数,数组
	WaitForMultipleObjects(2, hThread, TRUE,INFINITE);
	printf("主线程结束");
	return 0;
}

在这里插入图片描述

内核模式下的同步对象

内核模式下创建线程

#include <ntddk.h>   

//获取进程的主模块路径
PCHAR PsGetProcessImageFileName(IN PEPROCESS Process);

VOID Unload(IN PDRIVER_OBJECT pDriverObject)
{
	KdPrint(("Goodbye driver\n"));
}

VOID  ThreadProc(PVOID Context)
{
	//首先创建一个事件,得到事件句柄
	PHANDLE phEvent = (PHANDLE)Context;
	KdPrint(("%s\n", PsGetProcessImageFileName(PsGetCurrentProcess())));
	PsTerminateSystemThread(0);
}

VOID CreateThreadTest()
{
	HANDLE hThread;
	HANDLE hProcess;
	NTSTATUS status;
	CLIENT_ID ClientId = { NULL };
	OBJECT_ATTRIBUTES oa;
	//创建system下的子线程
	PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, NULL, NULL, NULL, ThreadProc, NULL);
	ClientId.UniqueProcess = (HANDLE)5132;//PID  进程下创建子线程5132是explorer.exe的PID
	InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
	status = ZwOpenProcess(&hProcess, PROCESS_ALL_ACCESS, &oa, &ClientId);
	if (NT_SUCCESS(status))
	{
		KdPrint(("打开进程成功\n"));
		//explorer.exe下创建子线程
		PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, NULL, hProcess, NULL, ThreadProc, NULL);
	}
	else 
	{
		KdPrint(("打开进程失败\n"));
	}
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath
)
{
	KdPrint(("hello driver\n"));
	DriverObject->DriverUnload = Unload;
	CreateThreadTest();
	return STATUS_SUCCESS;
}

在这里插入图片描述

内核模式下的事件

对象数据类型描述
Event(事件)KEVENT阻塞一个线程直到其他线程检测到某事件发生
Semaphore(信号灯)KSEMAPHORE与事件对象相似,但可以满足任意数量的等待
Mutex(互斥)KMUTEX执行到关键代码段时,禁止其他线程执行该代码段
Timer( 定时器)KTIMER推迟线程执行一段时期
Thread(线程)KTIMER阻塞一个线程直到另一个线程结束
#include <ntddk.h>   

VOID Unload(IN PDRIVER_OBJECT pDriverObject)
{
	KdPrint(("Goodbye driver\n"));
}

VOID  ThreadProc1(PVOID Context)
{
	//首先创建一个事件,得到事件句柄
	PKEVENT pEvent = (PKEVENT)Context;
	KdPrint(("进入线程1\n"));
	KeSetEvent(pEvent, IO_NO_INCREMENT, FALSE);
	PsTerminateSystemThread(0);
	KdPrint(("离开线程1\n"));
}

VOID EventTest() 
{
	KEVENT Event;//存放在栈上;
	HANDLE hThread;
	KeInitializeEvent(&Event, NotificationEvent, FALSE);
	PsCreateSystemThread(&hThread,THREAD_ALL_ACCESS,NULL,NULL,NULL,ThreadProc1,&Event);
	KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
	KdPrint(("主线程结束\n"));
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath
)
{
	KdPrint(("hello driver\n"));
	DriverObject->DriverUnload = Unload;
	EventTest();
	return STATUS_SUCCESS;
}

在这里插入图片描述

内核模式下的信号灯

#include <ntddk.h>   

VOID Unload(IN PDRIVER_OBJECT pDriverObject)
{
	KdPrint(("Goodbye driver\n"));
}

VOID  ThreadProc(PVOID Context)
{
	//首先创建一个事件,得到事件句柄
	LARGE_INTEGER timeout;
	timeout.QuadPart = -10 * 2000 * 1000;
	PKSEMAPHORE pSemaphore = (PKSEMAPHORE)Context;
	KdPrint(("进入系统线程函数\n"));
	//等待2秒钟
	KeDelayExecutionThread(KernelMode, FALSE, &timeout);
	KeReleaseSemaphore(pSemaphore, IO_NO_INCREMENT, 1, FALSE);
	KdPrint(("离开系统线程函数\n"));
	PsTerminateSystemThread(0);
}

VOID SemaphoreTest()
{
	KSEMAPHORE Semaphore;
	LONG Count;
	HANDLE hThread;
	KeInitializeSemaphore(&Semaphore, 2, 2);//参数2:当前有多少个  参数3:最大有多少个
	Count = KeReadStateSemaphore(&Semaphore);
	KdPrint(("%d\n", Count));

	KeWaitForSingleObject(&Semaphore, Executive, KernelMode, FALSE, NULL);//参数2:当前有多少个  参数3:最大有多少个
	Count = KeReadStateSemaphore(&Semaphore);
	KdPrint(("%d\n", Count));

	KeWaitForSingleObject(&Semaphore, Executive, KernelMode, FALSE, NULL);//参数2:当前有多少个  参数3:最大有多少个
	Count = KeReadStateSemaphore(&Semaphore);
	KdPrint(("%d\n", Count));

	PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, NULL, NULL, NULL, ThreadProc, &Semaphore);

	KeWaitForSingleObject(&Semaphore, Executive, KernelMode, FALSE, NULL);//参数2:当前有多少个  参数3:最大有多少个

	KdPrint(("结束"));
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath
)
{
	KdPrint(("hello driver\n"));
	DriverObject->DriverUnload = Unload;
	SemaphoreTest();
	return STATUS_SUCCESS;
}

在这里插入图片描述

内核模式下的互斥器

#include <ntddk.h>   

VOID Unload(IN PDRIVER_OBJECT pDriverObject)
{
	KdPrint(("Goodbye driver\n"));
}

VOID  ThreadProc1(PVOID Context)
{
	//多少个纳秒为单位,负号表示相对大小表示有十个纳秒表示一微秒。*2000表示多少毫秒,1000表示多少秒
	LARGE_INTEGER timeout;
	timeout.QuadPart = -10 * 2000 * 1000;
	PKMUTEX pMutex = (PKMUTEX)Context;
	KeWaitForMutexObject(pMutex, Executive, KernelMode, FALSE, NULL);
	KdPrint(("进入线程1\n"));
	KeDelayExecutionThread(KernelMode, FALSE, &timeout);
	KdPrint(("离开线程1\n"));
	KeReleaseMutex(pMutex, FALSE);
	PsTerminateSystemThread(0);
}

VOID  ThreadProc2(PVOID Context)
{
	//多少个纳秒为单位,负号表示相对大小表示有十个纳秒表示一微秒。*2000表示多少毫秒,1000表示多少秒
	LARGE_INTEGER timeout;
	timeout.QuadPart = -10 * 2000 * 1000;
	PKMUTEX pMutex = (PKMUTEX)Context;
	KeWaitForMutexObject(pMutex, Executive, KernelMode, FALSE, NULL);
	KdPrint(("进入线程2\n"));
	KeDelayExecutionThread(KernelMode, FALSE, &timeout);
	KdPrint(("离开线程2\n"));
	KeReleaseMutex(pMutex, FALSE);
	PsTerminateSystemThread(0);
}
VOID MutexTest()
{
	KMUTEX Mutex;
	HANDLE hThread[2] = { NULL };
	PETHREAD Thread[2] = { NULL };
	KeInitializeMutex(&Mutex, 0);
	PsCreateSystemThread(&hThread[0], THREAD_ALL_ACCESS, NULL, NULL, NULL, ThreadProc1, &Mutex);
	PsCreateSystemThread(&hThread[1], THREAD_ALL_ACCESS, NULL, NULL, NULL, ThreadProc2, &Mutex);

	ObReferenceObjectByHandle(hThread[0], THREAD_ALL_ACCESS, *PsThreadType, KernelMode, &Thread[0], NULL);
	ObReferenceObjectByHandle(hThread[1], THREAD_ALL_ACCESS, *PsThreadType, KernelMode, &Thread[1], NULL);

	KeWaitForMultipleObjects(2, Thread, WaitAll, Executive, KernelMode, FALSE, NULL, NULL);

	ObDereferenceObject(Thread[0]);//减少对象引用次数
	ObDereferenceObject(Thread[1]);
	KdPrint(("主线程结束\n"));
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath
)
{
	KdPrint(("hello driver\n"));
	DriverObject->DriverUnload = Unload;
	MutexTest();
	return STATUS_SUCCESS;
}

在这里插入图片描述

其他内核同步要素

服务函数描述
ExAcquireFastMutex()获取快速互斥,如果必要则等待
ExAcquireFastMutexUnsafe()获取快速互斥,如果必要则等待,调用者必须先停止接受APC
ExInitializeFastMutex()初始化快速互斥对象
ExReleaseFastMutex()释放快速互斥
ExReleaseFastMutexUnsafe()释放快速互斥 ,不解除APC提交禁止
ExTryToAcquireFastMutex()获取快速互斥,如果可能,立即获取不等待

快速互斥器

#include <ntddk.h>   

VOID Unload(IN PDRIVER_OBJECT pDriverObject)
{
	KdPrint(("Goodbye driver\n"));
}

VOID  ThreadProc1(PVOID Context)
{
	//多少个纳秒为单位,负号表示相对大小表示有十个纳秒表示一微秒。*2000表示多少毫秒,1000表示多少秒
	LARGE_INTEGER timeout;
	timeout.QuadPart = -10 * 2000 * 1000;
	PFAST_MUTEX pFastMutex = (PFAST_MUTEX)Context;
	ExAcquireFastMutex(pFastMutex);
	KdPrint(("进入线程1\n"));
	KeDelayExecutionThread(KernelMode, FALSE, &timeout);
	KdPrint(("离开线程1\n"));
	ExReleaseFastMutex(pFastMutex);
	PsTerminateSystemThread(0);
}

VOID  ThreadProc2(PVOID Context)
{
	//多少个纳秒为单位,负号表示相对大小表示有十个纳秒表示一微秒。*2000表示多少毫秒,1000表示多少秒
	LARGE_INTEGER timeout;
	timeout.QuadPart = -10 * 2000 * 1000;
	PFAST_MUTEX pFastMutex = (PFAST_MUTEX)Context;
	ExAcquireFastMutex(pFastMutex);
	KdPrint(("进入线程2\n"));
	KeDelayExecutionThread(KernelMode, FALSE, &timeout);
	KdPrint(("离开线程2\n"));
	ExReleaseFastMutex(pFastMutex);
	PsTerminateSystemThread(0);
}
VOID FastMutexTest()
{
	FAST_MUTEX FastMutex;
	HANDLE hThread1, hThread2;
	PETHREAD Thread[2] = { NULL };
	ExInitializeFastMutex(&FastMutex);
	PsCreateSystemThread(&hThread1, THREAD_ALL_ACCESS, NULL, NULL, NULL, ThreadProc1, &FastMutex);
	PsCreateSystemThread(&hThread2, THREAD_ALL_ACCESS, NULL, NULL, NULL, ThreadProc2, &FastMutex);
	//需要等待两个线程结束,如果不等待就会造成栈上的数据被释放,这里面就是一个无效内存容易引起崩溃
	//可以通过句柄找取线程对象
	ObReferenceObjectByHandle(hThread1, THREAD_ALL_ACCESS, *PsThreadType, KernelMode, &Thread[0], NULL);
	ObReferenceObjectByHandle(hThread2, THREAD_ALL_ACCESS, *PsThreadType, KernelMode, &Thread[1], NULL);
	//等待多个对象
	KeWaitForMultipleObjects(2, Thread, WaitAll, Executive, KernelMode, FALSE, NULL, NULL);
	//我们在引用的时候为了让他正常的释放,写出对这个对象的引用
	ObDereferenceObject(Thread[0]);
	ObDereferenceObject(Thread[1]);
	KdPrint(("主线程结束\n"));
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath
)
{
	KdPrint(("hello driver\n"));
	DriverObject->DriverUnload = Unload;
	FastMutexTest();
	return STATUS_SUCCESS;
}

在这里插入图片描述

原子集操作

服务函数描述
InterlockedCompareExchange比较并有条件地交换两个值
InterlockedDecrement整数减1
InterlockedExchange交换两个值
InterlockedExchangeAdd加两个值并返回原始值
InterlockedIncrement整数加1
ExInterlockedAddLargeInteger向64位整数数加
ExInterlockedAddLargeStatistic向ULONG加
ExInterlockedAddUlong向ULONG加并返回原始值
ExInterlockedCompareExchange64交换两个64位置
#include <ntddk.h>   

VOID Unload(IN PDRIVER_OBJECT pDriverObject)
{
	KdPrint(("Goodbye driver\n"));
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath
)
{
	KdPrint(("hello driver\n"));
	DriverObject->DriverUnload = Unload;
	LONG Value = 10;
	InterlockedCompareExchange(&Value, 100, 10);
	KdPrint(("InterlockedCompareExchange(&Value, 100, 10):%d\n",Value));

	InterlockedDecrement(&Value);
	KdPrint(("InterlockedDecrement(&Value):%d\n", Value));

	InterlockedExchange(&Value,55);
	KdPrint(("InterlockedExchange(&Value,55):%d\n", Value));

	KdPrint(("返回原始值:%d\n", InterlockedExchangeAdd(&Value, 1)));
	KdPrint(("InterlockedExchangeAdd(&Value, 1):%d\n", Value));

	InterlockedIncrement(&Value);
	KdPrint(("InterlockedIncrement(&Value):%d\n", Value));

	LARGE_INTEGER liValue;
	liValue.QuadPart = 10;
	LARGE_INTEGER liIncre;
	liIncre.QuadPart = 900;
	KSPIN_LOCK spinLock;

	LONGLONG value1 = 1, value2 = 2, value3 = 3 ;

	KdPrint(("***************************"));
	KeInitializeSpinLock(&spinLock);
	ExInterlockedAddLargeInteger(&liValue, liIncre, &spinLock);
	KdPrint(("InterlockedIncrement:%d\n", liValue.LowPart));

	ExInterlockedAddLargeStatistic(&liValue,9);
	KdPrint(("ExInterlockedAddLargeStatistic:%d\n", liValue.LowPart));

	ExInterlockedAddUlong(&Value, 10, &spinLock);
	KdPrint(("Exchange64:%d\n", Value));
	ExInterlockedCompareExchange64(&value1, &value2, &value3, &spinLock);
	KdPrint(("Exchange64:%d\n", value1));
	return STATUS_SUCCESS;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值