事件
事件可以完全控制,其他无法控制线程的执行顺序,但是事件对象可以做到。
***事件(Event)***是在线程同步中最常使用的一种同步对象,事件包含一个使用计数,一个是用来表示自动重置/手动重置的布尔值,另一个是表示事件有没有触发的布尔值。
事件对象有两种状态: 1、手动状态。2、自动状态
手动状态事件对象的激发态和非激发态是由我们来控制,自动状态与互斥体类似。
事件与互斥体区别
事件对象没有拥有者的概念,谁都可以操作事件对象的状态。事件可以控制线程的执行顺序。
手动状态事件对象的激发态和非激发态是由我们来控制,自动状态与互斥体类似。
在使用正常线程创建调用回调函数时,线程的执行顺序不一定会按线程创建的顺序执行。
#include<iostream>
#include<Windows.h>
LONG g_count;
HANDLE hEvent;
DWORD WINAPI myThreadProc1(
_In_ LPVOID lpParameter
)
{
printf("线程1执行了\n");
return 0;
}
DWORD WINAPI myThreadProc2(
_In_ LPVOID lpParameter
)
{
printf("线程2执行了\n");
return 0;
}
DWORD WINAPI myThreadProc3(
_In_ LPVOID lpParameter
)
{
printf("线程3执行了\n");
return 0;
}
int main()
{
//hEvent = CreateEventW(NULL, FALSE, TRUE, L"dsd");
HANDLE hThread1 = CreateThread(0, 0, myThreadProc1, 0, 0,0);
HANDLE hThread2 = CreateThread(0, 0, myThreadProc2, 0, 0,0);
HANDLE hThread3 = CreateThread(0, 0, myThreadProc3, 0, 0,0);
WaitForSingleObject(hThread1, -1);
WaitForSingleObject(hThread2, -2);
printf("%d\n", g_count);
CloseHandle(hThread1);
CloseHandle(hThread2);
return 0;
}
而我们如果使用Event事件就可以对线程的执行顺序进行实现。
信号量
信号量也没有拥有者的概念,但是他有数量。
信号量有一个当前信号数,只要这个数不为0,信号量就处于激发态。
当有线程调用WaitForSingle0bject后,信号数减1,如果不为0的话,再有线程调用
WaitForSingleObject.会继续上一把锁。相反调用ReleaseSemaphoore会将信号量加1,。如果信号量为0,当有线程调用WaitForSingleObject.时,线程会被阻塞。
使用场景:多开数量检测
操纵信号量实现游戏多开访问控制
#include<iostream>
#include<Windows.h>
int main() {
HANDLE hSema = OpenSemaphoreW(EVENT_ALL_ACCESS, FALSE, L"dsd");//获取信号量句柄
if (!hSema)//如果没有成功打开即创建信号量,仅当CreateSemaphore创建信号灯时才会成功
{
hSema = CreateSemaphore(NULL, 0, 3, L"dsd");//创建或打开信号灯对象,返回信号灯句柄
}
BOOL hSuccess = ReleaseSemaphore(hSema,1,NULL);//如果成功信号量加1则返回TRUE,否则返回FALSE
if (!hSuccess) {
MessageBox(0, L"程序打开数量不能超过三个",L"提示",MB_OK);
CloseHandle(hSema);
return 0;
}
system("pause");
return 0;
}