互斥体
一、什么是内核对象
内核对象可以是进程也可以是线程或者是互斥体等,是在内核中创建的,是一个结构体,结构体里面有个成员用来计数的,我们常用的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;
}