互斥体

一、什么是内核对象

内核对象可以是进程也可以是线程或者是互斥体等,是在内核中创建的,是一个结构体,结构体里面有个成员用来计数的,我们常用的CloseHandle只是用来关闭句柄然后计数器减一,并没有销毁内核对象,之有当计数器为0才会销毁内核对象

1、WaitForSingleObject

功能:

等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止.

参数:

  • 内核对象句柄
  • 等待时间(-1是一直等)

2、WaitForMultipleObjects

参数:

  • 要查看内核对象的数量
  • 内核对象数组
  • 等到类型(TRUE 等到所有变为已通知 FALSE 只要有一个变为已通知)
  • 等待时间

二、通知状态

1、内核对象中的每种对象都可以说是处于已通知或未通知的状态之中

2、这种状态的切换是由Microsoft为每个对象建立的一套规则来决定的

3、当线程正在运行的时候,线程内核对象处于未通知状态

4、当线程终止运行的时候,它就变为已通知状态

5、在内核中就是个BOOL值,运行时FALSE 结束TRUE

三、互斥体

1、互斥体和临界区的区别

  • 临界区只能用于单个进程间的线程控制.

  • 互斥体可以设定等待超时,但临界区不能.

  • 线程意外终结时,Mutex可以避免无限等待.

  • Mutex效率没有临界区高.

  • 互斥体是在内核创建的

2、创建互斥体

CreateMutex在创建成功时会返回一个句柄,此时我们再创建一个互斥体名字一样,也会返回一个句柄,这个句柄和前面的句柄是同一个,因为是在内核中创建的,并且会返回个错误信息,错误信息为ERROR_ALREADY_EXISTS

参数:

  • 安全描述符
  • 是否有信号(有信号为FALSE,没信号为TRUE)
  • 名称名(随便取)

3、获取令牌

WaitForSingleObject

参数:

  • 句柄
  • 等待时间

4、释放令牌

ReleaseMutex
参数:

  • 句柄

5、OpenMutex

参数:

  • 以什么权限打开(MUTEX_ALL_ACCESS是拥有所有权限)
  • 打开的互斥体是否可以被继承
  • 打开的互斥体名字

6、演示

A程序

#include "stdafx.h"
#include "windows.h"

int main(int argc, char* argv[])
{
	HANDLE g_hMutex = CreateMutex(NULL,FALSE, "XYZ");
	
	Sleep(5000);
	
	WaitForSingleObject(g_hMutex,INFINITE);
	
	printf("A");
	ReleaseMutex(g_hMutex);
	
	getchar();
	return 0;
}

B程序

#include "stdafx.h"
#include <windows.h>

int main(int argc, char* argv[])
{
	
	HANDLE g_hMutex = OpenMutex(MUTEX_ALL_ACCESS,FALSE, "XYZ");
	
	WaitForSingleObject(g_hMutex,INFINITE);
	
	for(int i=0;i<10;i++)
	{
        Sleep(1000);
		printf("B+++++%d\n",i);
	}
	
	ReleaseMutex(g_hMutex);
	
	getchar();
	return 0;
}

先运行A程序,在运行B程序就会发现B先打印,打印时A在等待,等B释放互斥体,A在执行

7、防止多开

多开

#include "stdafx.h"
#include "windows.h"
int main(int argc, char* argv[])
{


    //创建令牌
    HANDLE g_mutex = CreateMutex(NULL,FALSE,"防止多开");
	/*
	DWORD DwRet = GetLastError();
	if(g_mutex)
	{
		if(DwRet == ERROR_ALREADY_EXISTS)
		{
			CloseHandle(g_mutex);
			return 0;
		}		
	}else
	{
		printf("创建失败");
		CloseHandle(g_mutex);
		return 0;
	}*/
	
    while(1)
    {
        Sleep(1000);
        printf("进程\n");
    }   
    return 0;
}

防止多开

#include "stdafx.h"
#include "windows.h"
int main(int argc, char* argv[])
{


    //创建令牌
    HANDLE g_mutex = CreateMutex(NULL,FALSE,"防止多开");
	
	DWORD DwRet = GetLastError();
	if(g_mutex)
	{
		if(DwRet == ERROR_ALREADY_EXISTS)
		{
			CloseHandle(g_mutex);
			return 0;
		}		
	}else
	{
		printf("创建失败");
		CloseHandle(g_mutex);
		return 0;
	}
	
    while(1)
    {
        Sleep(1000);
        printf("进程\n");
    }   
    return 0;
}

四、事件

1、CreateEvent

参数:

  • 安全描述符
  • 是否是通知类型(TRUE是通知类型,FALSE是互斥体)
  • 是否有信号(TRUE是有信号,FALSE是无信号)
  • 名字
#include "stdafx.h"
#include "windows.h"


HANDLE	g_hEvent;
DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
	WaitForSingleObject(g_hEvent,INFINITE); //创建的事件是互斥类型,此时会将状态改变

	printf("执行ThreadProc1\n");

	//设置事件为通知
	SetEvent(g_hEvent);
	return 0;

}

DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
	//等待线程发生变化
	WaitForSingleObject(g_hEvent,INFINITE); //创建的事件是互斥类型,此时会将状态改变

	printf("执行ThreadProc2\n");

	//设置事件为通知
	SetEvent(g_hEvent);
	return 0;

}

int main(int argc, char* argv[])
{

	//创建一个事件对象,默认安全属性 、TRUE通知/FALSE互斥、初始状态、名字
	g_hEvent  = CreateEvent(NULL,FALSE,FALSE,NULL);

	//创建线程
	HANDLE ArrhThread[2];
	ArrhThread[0] = CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);
	ArrhThread[1] = CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);
	
	//设置事件为通知
	SetEvent(g_hEvent);
	
	//等待线程结束,关闭句柄
	WaitForMultipleObjects(2,ArrhThread,TRUE,INFINITE);
	CloseHandle(ArrhThread[0]);
	CloseHandle(ArrhThread[1]);
	getchar();
    return 0;
}

事件的好处就是,当线程没有调度权时,cpu不会为它分配时间,而临界区没有调度权它也会将时间片耗尽,浪费CPU

五、信号量

1、CreateSemaphore

参数

  • 安全描述符
  • 初始资源数量。0时不发送信号,但是不能大于第三个参数(lMaximumCount)
  • 最大并发数量
  • 名字
#include "stdafx.h"
#include "windows.h"

HANDLE hSemaphore;


DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
	WaitForSingleObject(hSemaphore, INFINITE);			

	DWORD* name = (DWORD*)lpParameter;
	for(int i=0;i<10;i++)
	{
		Sleep(100);
		printf("%d++++%d\n",i,*name);
	}
	ReleaseSemaphore(hSemaphore, 1, NULL);
	return 0;

}


int main(int argc, char* argv[])
{
	HANDLE hThread[3];
	DWORD x =1;
	DWORD y =2;
	DWORD z =3;
	hSemaphore= CreateSemaphore(NULL,0,3,NULL);
					

	hThread[0] = CreateThread(NULL, 0, ThreadProc,&x, 0, NULL);			
	hThread[1] = CreateThread(NULL, 0, ThreadProc,&y, 0, NULL);			
	hThread[2] = CreateThread(NULL, 0, ThreadProc,&z, 0, NULL);			
	
        //递增信号量的当前资源计数			
	ReleaseSemaphore(hSemaphore, 2, NULL);

	WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
	CloseHandle(hThread[0]);
	CloseHandle(hThread[1]);
	CloseHandle(hThread[2]);
	CloseHandle(hSemaphore);
	getchar();
    return 0;
}

posted @ 2021-12-20 22:12  lnterpreter  阅读(401)  评论(0编辑  收藏  举报