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一下,设置好等待时间,如果超过时间,就说明已经达到指定的个数了。就可以结束程序。
相关文章推荐
- 20170716Windows11_4_信号量/互斥体/程序单开应用
- 20170716Windows11_4_信号量/互斥体/程序单开应用
- 20170716Windows11_4_信号量/互斥体/程序单开应用
- 20170716Windows11_4_信号量/互斥体/程序单开应用
- 20170716Windows11_4_信号量/互斥体/程序单开应用
- 20170716Windows11_4_信号量/互斥体/程序单开应用
- 20170716Windows11_4_信号量/互斥体/程序单开应用
- 20170716Windows11_4_信号量/互斥体/程序单开应用
- C#如何为winform程序打包发布应用(图解)
- C++ 容器的综合应用的一个简单实例——文本查询程序
- Win10 IoT C#开发 2 - 创建基于XAML的UI程序 及 应用的三种部署方法
- android之查看图片的程序 ImageSwitcher Gallery的配合应用---版本2
- Ninject之旅之十二:Ninject在Windows Form程序上的应用(附程序下载)
- 安卓应用开发实战:[2]修改程序名称&标题我们首先看一下程序没修改之前的应用名称和标题的显示效果,可见默认是用工程名字来命名的。
- Ubuntu 16.04 MPICH应用2——简单程序测试
- Android应用开发多个activity完全退出程序方法
- 关于格雷码在 FPGA 程序调试中的应用
- IOS6.0 应用内直接下载程序 不需跳转AppStore
- c# 程序设计及应用教程上机A.2.3————字符提取和整数整除联系(Console)
- Windows平台下程序日志的设计和实现(上:设计、实现和应用)