您的位置:首页 > 其它

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

2017-07-16 23:29 330 查看

信号量:

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一下,设置好等待时间,如果超过时间,就说明已经达到指定的个数了。就可以结束程序。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: