20170716Windows11_4_信号量/互斥体/程序单开应用

信号量:

1:可能有需求需要知道能够启动多少次,允许启动多少次,信号量就是用于解决这个的。
2:HANDLE hSemaphore = CreateSemaphore(nullptr, 0, 20, TEXT("Demo"));,其中,第三个参数决定这个信号量最大能够被Wait多少次,每一次的wait都会使里面的计数递减(这个计数并不是使用计数),当Count为0的时候,就会一直未wait状态。
3:第二个参数为起始个数,如果为0,那么后面紧跟着的WaitForSingleObject(hSemaphore, INFINITE);就会被卡住。
    特别注意,起始个数不一定小于第三个参数最大值。
4:
#include <windows.h>

int main()
{
	HANDLE	 hSemaphore = CreateSemaphore(nullptr, 1, 20, TEXT("Demo"));
//	OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, TEXT("Demo"));
	ReleaseSemaphore(hSemaphore, 2, nullptr);//设置再添加的次数
	//如果原来设置只能启动一次,那么现在就变为了3次。
	WaitForSingleObject(hSemaphore, INFINITE);
	WaitForSingleObject(hSemaphore, INFINITE);
	WaitForSingleObject(hSemaphore, INFINITE);
	WaitForSingleObject(hSemaphore, INFINITE);//会一直停在这一步
	WaitForSingleObject(hSemaphore, INFINITE);

	return 0;
}

5:使用ReleaseSemaphore()可以增加允许启动的次数。

互斥体:

1:是Windows里面比较常用也比较特殊的内核对象,互斥体里面会保持一个线程ID的对象,他决定这个内核对象处于Signal状态还是noSignal状态。
2:当线程ID为0的时候,处于有信号状态,线程可被激活后,会将激活他的这个内核对象的线程ID传到这个内核对象里面,会使这个内核对象又变成noSignal状态,他与之前学的关键段(临界区)类似,互斥体长期用来做线程同步。
3:
HANDLE WINAPI CreateMutex(
  _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,//安全指针
  _In_     BOOL                  bInitialOwner,	//初始化线程的时候,是否拥有他。即是否需要将线程ID传递进去。如果需要传递进去,Mutex就变成了无信号状态
  _In_opt_ LPCTSTR               lpName		//互斥体名称
);

4:但是Mutex是和线程绑定的,只要线程有信号(在主线程中),无论Wait多少次,都是可以通过的。但是,在其他线程里面,就会不一样。
#include <windows.h>
#include <process.h>

int main()
{
	HANDLE hMutex = CreateMutex(nullptr, TRUE, nullptr);//Mutex为noSignal状态
	WaitForSingleObject(hMutex, INFINITE);
	WaitForSingleObject(hMutex, INFINITE);
	WaitForSingleObject(hMutex, INFINITE);
	WaitForSingleObject(hMutex, INFINITE);//都可以通过。

	return 0;
}

5:在自己新建的线程里面:
#include <windows.h>
#include <process.h>

HANDLE gMutex;

unsigned __stdcall ThreadFun(LPVOID lParam)
{
	WaitForSingleObject(gMutex, INFINITE);//不会通过,Mutex处于noSignal状态
	return 0;
}

int main()
{
	gMutex = CreateMutex(nullptr, TRUE, nullptr);//Mutex为noSignal状态
	HANDLE hThread = (HANDLE)_beginthreadex(nullptr, 0, ThreadFun, nullptr, 0, nullptr);
//	ReleaseMutex(gMutex);//释放后,就变为有信号状态。
	WaitForSingleObject(hThread, INFINITE);

	return 0;
}

注意:如果上面是用来ReleaseMutex,那么,就变味有信号状态,自己创建的线程里面的Wait就可以通过了。
6:通常,我们不会将第二个参数传递为TRUE(传递进了线程ID),这种情况下,子线程里面就可以直接通过Wait。
#include <windows.h>
#include <process.h>

HANDLE gMutex;

unsigned __stdcall ThreadFun(LPVOID lParam)
{
	WaitForSingleObject(gMutex, INFINITE);//不会通过,Mutex处于noSignal状态
	return 0;
}

int main()
{
	gMutex == CreateMutex(nullptr, FALSE, nullptr);
	HANDLE hThread = (HANDLE)_beginthreadex(nullptr, 0, ThreadFun, nullptr, 0, nullptr);
	WaitForSingleObject(hThread, INFINITE);
	return 0;
}

7:总结:
        Mutex为一个较为特殊的内核对象,里面记录有拥有他的线程ID,互斥体内核对象的信号的成员变量也会随着线程ID发生变化。如果互斥体没有被某个线程拥有,即线程ID为0时(传递的FALSE),那么互斥体就处于有信号状态。当有任何一个线程ID的时候,就变为了无信号状态。此时,必须使用ReleaseMutex释放这个互斥体,他才能够被其他的线程来使用。
8:
#include <windows.h>
#include <process.h>

HANDLE gMutex;

unsigned __stdcall ThreadFun(LPVOID lParam)
{
	WaitForSingleObject(gMutex, INFINITE);//不会通过,gMutex被主线程拥有。
	return 0;
}

int main()
{
	gMutex = CreateMutex(nullptr, FALSE, nullptr);//创建,没有将线程ID放在互斥体里面
	WaitForSingleObject(gMutex, INFINITE);//将导致当前线程拥有这个互斥体,会导致上面的wait不会通过。
//	ReleaseMutex(gMutex);//如果这里释放掉了,那么创建线程里面的wait就可以通过。
	HANDLE hThread = (HANDLE)_beginthreadex(nullptr, 0, ThreadFun, nullptr, 0, nullptr);
	WaitForSingleObject(hThread, INFINITE);

	return 0;
}

9:上面代码,如果将main函数里面,多写一些WaitForSingleObject(gMutex, INFINITE);,实际上,他还是可以通过的,但是,我们会发现创建的线程里面的Wait就不会通过了,这是因为,Mutex里面有一个类似于使用计数的等待计数,与信号量的计数有点类似,等待计数会随着每一次等待递增,随着Release递减,因此,创建线程里面的不会通过。只要保证main里面wait和Release一样多,那么其他线程就可以使用该互斥体。
10:当进行释放的时候,ReleaseMutex的时候,他会检查释放地点是否为拥有这个互斥体的线程ID,如果不是,就不行,例如,在上面的程序中,main里面多次Wait而不Release,而在创建线程的回调函数里面Release很多次,在Wait,这样任然是不可以通过Wait的。
11:互斥体与线程之间的绑定,有一个所属线程的概念,使得可以用来做线程同步。可以用来做游戏里面的防止多开。

程序单开应用:

1:内核对象是被内核所拥有,是属于操作系统的,所有的内核对象都是可以跨进程通讯的,A进程拥有一个内核对象,B进程也可以使用该内核对象。通过互斥体可以避免一个程序被多次打开,也可以使用信号量来确保打开不能超过多少个。
2:
#include <windows.h>
#include <tchar.h>


int main()
{
	HANDLE hMutex = CreateMutex(NULL, TRUE, TEXT("Demo"));
	if (GetLastError() == ERROR_ALREADY_EXISTS)
	{
		_tprintf(TEXT("Is Exists..."));
		return 1;
	}
	WaitForSingleObject(hMutex, INFINITE);//可以通过,此主线程已近拥有所有权了。占住了hMutex的所有权。
	if (hMutex == NULL)
	{
		_tprintf(TEXT("hMutex = NULL"));
	}
	while (TRUE)//确保不退出
	{
		Sleep(1000);
	}

	return 0;
}

3:以同样的原理,使用信号量可以控制程序启动不超过一定的个数。只需要在创建好信号量后(第二次打开程序则为打开信号量),每次都Wait一下,设置好等待时间,如果超过时间,就说明已经达到指定的个数了。就可以结束程序。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值