一、互斥锁
1、先熟悉熟悉API
1,创建互斥锁,并反正一个句柄
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTESlpMutexAttributes, // 指向安全属性的指针
BOOLbInitialOwner, // 初始化互斥对象的所有者,一般设置为FALSE
LPCTSTRlpName // 互斥对象名
);
2,释放互斥对象的控制权
BOOL ReleaseMutex(
HANDLE hMutex //已创建Mutex的句柄
);
3,打开互斥锁,返回句柄
HANDLE OpenMutex(
DWORDdwDesiredAccess, // 互斥体的访问权限
BOOLbInheritHandle, //如希望子进程能够继承句柄,则为TRUE
LPCTSTRlpName // 互斥锁名字
);
4,等待目标返回
DWORD WaitForSingleObject(
HANDLE hHandle, //目标句柄
DWORD dwMilliseconds //等待时间 ,毫秒记,INFINITE为永久等待
);
一个简单的互斥锁例子来实现多线程同步
#include<Windows.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
static int g_count = 100;
class Lock
{
public:
Lock(char*szName)
{
hd = OpenMutex(MUTEX_ALL_ACCESS, NULL, (LPCWSTR)szName);
WaitForSingleObject(hd, INFINITE);
Sleep(1500);//测试用:等待1.5秒,正式类中不应有
}
~Lock()
{
ReleaseMutex(hd);
}
static bool InitLock(char*szName)
{
if (!OpenMutex(MUTEX_ALL_ACCESS, NULL, (LPCWSTR)szName))
{
if (!CreateMutex(NULL, NULL, (LPCWSTR)szName))
return false;
return true;
}
return false;
}
HANDLE hd;
};
UINT address1(LPVOID lparam)
{
while (1)
{
Lock lc("_temp_lock");
cout << g_count-- << "---" << "address1" << endl;
}
}
UINT address2(LPVOID lparam)
{
while (1)
{
Lock lc("_temp_lock");
cout << g_count-- << "---" << "address2" << endl;
}
}
int main(int argc, char*argv[])
{
if(!Lock::InitLock("_temp_lock"))//创建互斥锁失败
return -1;
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address1, NULL, NULL, NULL);//开启线程1
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address2, NULL, NULL, NULL);//开启线程2
system("pause");
return 0;
}
原理浅析:Lock::InitLock()来创建互斥锁,在本demo中,同步是按照CreateThread的创建顺序。创建了一个Lock类,当生成对象的时候就等待,一旦当互斥锁没有控制权,等待即结束,便向下执行,对象析构的时候就释放控制权,以此类推循环。
ps:mutex作用范围在系统层,使用mutex效率并不是太高,使用临界区(作用范围在进程)效率比较高
二、信号量
1,先熟悉熟悉API
CreateSemaphore() 创建一个信号量
OpenSemaphore() 打开一个信号量
ReleaseSemaphore() 释放信号量
WaitForSingleObject() 等待信号量
2,举个简单的小例子
#include <stdio.h>
#include <Windows.h>
#define THREAD_NUM 20
#define SEM_NAME "THREAD_SEMAPHORE"
HANDLE g_hSem = NULL;
HANDLE g_hThread[THREAD_NUM];
void WINAPI ThreadFun(void* param)
{
printf("进入线程: %u,并等待\n", GetCurrentThreadId());
WaitForSingleObject(g_hSem, INFINITE);
printf("线程: %u 获得信号量\n", GetCurrentThreadId());
long dwSem = 0;
if (!ReleaseSemaphore(g_hSem, 1, &dwSem))
return;
printf("目前资源数:%u\n", dwSem);
}
int main(int argc, char*argv[])
{
g_hSem = CreateSemaphoreA(NULL, 0, 5, SEM_NAME);
g_hSem = OpenSemaphoreA(SEMAPHORE_MODIFY_STATE, FALSE, SEM_NAME);
for (int i = 0; i < THREAD_NUM; ++i)
{
DWORD dwThreadID = 0;
g_hThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFun, NULL, 0, &dwThreadID);
}
WaitForMultipleObjects(THREAD_NUM, g_hThread, TRUE, INFINITE);
printf("全部执行完了\n");
return 0;
}
ps:信号量可以说在平常的使用中用的比较少,一般的用途在控制并发线程数量,抢占资源问题。
三、事件
1,先熟悉熟悉API
HANDLE CreateEvent( //创建事件
LPSECURITY_ATTRIBUTES lpEventAttributes,// 安全属性
BOOL bManualReset,// 复位方式
BOOL bInitialState,// 初始状态
LPCTSTR lpName // 对象名称
);
HANDLE OpenEvent( //打开事件
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);
BOOL ResetEvent(//事件对象设置为无信号状态。
HANDLE hEvent
);
BOOL SetEvent(HANDLE hEvent);//事件对象设置为有信号状态。
BOOL PulseEvent(HANDLE hEvent)//事件对象设置为有信号状态,脉冲一个事件
WaitForSingleObject() 等待信号量
2,举个简单的小例子
#include <stdio.h>
#include <Windows.h>
HANDLE g_hEvent;
UINT address1(LPVOID lparam)
{
printf("进入线程了,等待5秒\n");
WaitForSingleObject(g_hEvent, INFINITE);
printf("等待结束了,向下执行了!\n");
return 0;
}
UINT address2(LPVOID lparam)
{
Sleep(5000);
SetEvent(g_hEvent);
return 0;
}
int main(int argc, char*argv[])
{
g_hEvent=CreateEvent(NULL, true, FALSE, NULL);
ResetEvent(g_hEvent);
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address1, NULL, NULL, NULL);//开启线程1
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address2, NULL, NULL, NULL);//开启线程2
system("pause");
return 0;
}
ps:本小例模拟了的两个线程间的同步,address2来控制address1的执行,事件在多线程程序中的应用比较多,比较重要,定要熟练掌握。
四、临界区
1,先熟悉熟悉API
void InitializeCriticalSection(//初始化临界区
LPCRITICAL_SECTION lpCriticalSection);
void WINAPI DeleteCriticalSection( //删除临界区
_Inout_ LPCRITICAL_SECTION lpCriticalSection);
VOID WINAPI EnterCriticalSection( //进入临界区
__inout LPCRITICAL_SECTION lpCriticalSection
);
VOID WINAPI LeaveCriticalSection(//离开临界区
_Inout_ LPCRITICAL_SECTION lpCriticalSection
);
2,举个简单的小例子
#include <stdio.h>
#include <Windows.h>
CRITICAL_SECTION g_cs;
int g_nIndex = 20;
UINT address1(LPVOID lparam)
{
while(true)
{
if (10 == g_nIndex)
return 1;
EnterCriticalSection(&g_cs);
printf("address111线程,index=%d\n",g_nIndex);
g_nIndex--;
LeaveCriticalSection(&g_cs);
}
return 0;
}
UINT address2(LPVOID lparam)
{
while (true)
{
if (0 == g_nIndex)
return 1;
EnterCriticalSection(&g_cs);
printf("address222线程,index=%d\n", g_nIndex);
--g_nIndex;
LeaveCriticalSection(&g_cs);
}
return 0;
}
int main(int argc, char*argv[])
{
InitializeCriticalSection(&g_cs);
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address1, NULL, NULL, NULL);//开启线程1
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address2, NULL, NULL, NULL);//开启线程2
system("pause");
DeleteCriticalSection(&g_cs);
return 0;
}
ps:小例中,address1被临界区一直占用到到address1退出,address2才能进入临界区,进行直到退出,与mutex交替执行不同,临界区比较简单且最易用。
这里写图片描述