不说原理,只说使用示例。
先统计下线程同步可以使用到的内容:
-
原子锁
InterlockedExchangeAdd()
-
旋转锁
InterlockedExchange()
-
关键段
InitializeCriticalSection()、DeleteCriticalSection()
EnterCriticalSection()、LeaveCriticalSection()
TryEnterCriticalSection()不等待,返回FALSE表示资源被用
InitializeCriticalSectionAndSpinCount()、SetCriticalSectionSpinCount()关键段与旋转锁配合
-
Slim读写锁
InitializeSRWLock()
写锁:AcquireSRWLockExclusive()、ReleaseSRWLockExclusive()
读锁:AcquireSRWLockShared()、ReleaseSRWLockShared()
-
事件和等待函数
等待函数:WaitForSingleObject()
CreateEvent()、ResetEvent()、SetEvent()
-
信号量和等待函数
CreateThread()、OpenSemaphore()、ReleaseSemaphore()
-
互斥锁/互斥量和等待函数
CreateMutex()、OpenMutex()、ReleaseMutex()
先看下面一段代码来简单说明一下为什么需要使用线程同步。
#include <Windows.h>
#include <stdio.h>
#define COUNT 100000
long g_x = 0;
DWORD WINAPI ThreadFunc(PVOID pPara);
int main(void)
{
HANDLE hThread_1 = NULL, hThread_2 = NULL;
DWORD ThreadID_1, ThreadID_2;
hThread_1 = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &ThreadID_1);
hThread_2 = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &ThreadID_2);
CloseHandle(hThread_1);
CloseHandle(hThread_2);
Sleep(1000);
printf("%d\n", g_x);
getchar();
return 0;
}
DWORD WINAPI ThreadFunc(PVOID pPara)
{
int tick = 0;
while (tick++ < COUNT)
{
g_x++;
}
return 0;
}
在COUNT比较大时,直接使用g_x++; 最后g_x得出的结果不会是COUNT的两倍,而且是一个不确定的数。这里的问题就是常见的资源抢占问题。因为g_x++;这句话在计算机执行时被分为三步执行。如果感兴趣了解为什么被分为三步就会出现问题,推荐去看看windows核心编程。这里不深究。
解决方法一,原子锁:
DWORD WINAPI ThreadFunc(PVOID pPara)
{
int tick = 0;
while (tick++ < COUNT)
{
//g_x++;
InterlockedExchangeAdd(&g_x, 1);
}
return 0;
}
解决方法二,旋转锁,谨慎使用:
unsigned int g_fResourceInUse = 0;
DWORD WINAPI ThreadFunc(PVOID pPara)
{
int tick = 0;
while (InterlockedExchange(&g_fResourceInUse, 1) == 1)
Sleep(0); //避免线程浪费CPU,及资源访问被拒绝。
while (tick++ < COUNT)
{
g_x++;
}
InterlockedExchange(&g_fResourceInUse, 0);
return 0;
}
解决方法三,关键段:
int main(void)
{
HANDLE hThread_1 = NULL, hThread_2 = NULL;
DWORD ThreadID_1, ThreadID_2;
if (0)
{
InitializeCriticalSection(&g_cs);
}else{
InitializeCriticalSectionAndSpinCount(&g_cs, 4000);
SetCriticalSectionSpinCount(&g_cs, 5000);
}
hThread_1 = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &ThreadID_1);
hThread_2 = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &ThreadID_2);
CloseHandle(hThread_1);
CloseHandle(hThread_2);
Sleep(1000);
printf("%d\n", g_x);
DeleteCriticalSection(&g_cs);
getchar();
return 0;
}
CRITICAL_SECTION g_cs;
DWORD WINAPI ThreadFunc(PVOID pPara)
{
int tick = 0;
EnterCriticalSection(&g_cs);
while (tick++ < COUNT)
{
g_x++;
}
LeaveCriticalSection(&g_cs);
return 0;
}
解决方法四,Slim读写锁:
int main(void)
{
SRWLOCK SRWLock;
InitializeSRWLock(&SRWLock);
AcquireSRWLockExclusive(&SRWLock);
g_x++;
ReleaseSRWLockExclusive(&SRWLock);
AcquireSRWLockShared(&SRWLock);
printf("%d\n", g_x);
ReleaseSRWLockShared(&SRWLock);
getchar();
return 0;
}
解决方法五,等待函数和事件:
HANDLE hTdEvent;
int main(void)
{
HANDLE hThread_1 = NULL, hThread_2 = NULL;
DWORD ThreadID_1, ThreadID_2;
hTdEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
hThread_1 = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &ThreadID_1);
hThread_2 = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &ThreadID_2);
CloseHandle(hThread_1);
CloseHandle(hThread_2);
SetEvent(hTdEvent);
Sleep(1000);
printf("%d\n", g_x);
getchar();
return 0;
}
DWORD WINAPI ThreadFunc(PVOID pPara)
{
int tick = 0;
WaitForSingleObject(hTdEvent, INFINITE);
ResetEvent(hTdEvent);
while (tick++ < COUNT)
{
g_x++;
}
SetEvent(hTdEvent);
return 0;
}
解决方法六,信号量和等待函数,可用于服务器连接数达到上限时拒绝访问:
OpenSemaphore();
HANDLE hSemaphore;
int main(void)
{
HANDLE hThread = NULL;
DWORD ThreadID;
if (1)
{
hSemaphore = CreateSemaphore(NULL, 1, 1, NULL);
}else{
hSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
ReleaseSemaphore(hSemaphore, 1, NULL);
}
hThread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &ThreadID);
CloseHandle(hThread);
Sleep(1);
WaitForSingleObject(hSemaphore, INFINITE);
printf("%d\n", g_x);
getchar();
return 0;
}
DWORD WINAPI ThreadFunc(PVOID pPara)
{
int tick = 0;
WaitForSingleObject(hSemaphore, INFINITE);
while (tick++ < COUNT)
{
g_x++;
}
ReleaseSemaphore(hSemaphore, 1, NULL);
return 0;
}
解决方法七,互斥锁/互斥量和等待函数:
#define MUTEX "MUTEX"
HANDLE hMutex;
int main(void)
{
HANDLE hThread_1 = NULL, hThread_2 = NULL;
DWORD ThreadID_1, ThreadID_2;
hMutex = CreateMutex(NULL, 0, MUTEX);
hThread_1 = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &ThreadID_1);
hThread_2 = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &ThreadID_2);
CloseHandle(hThread_1);
CloseHandle(hThread_2);
Sleep(1000);
printf("%d\n", g_x);
getchar();
return 0;
}
DWORD WINAPI ThreadFunc(PVOID pPara)
{
int tick = 0;
WaitForSingleObject(hMutex, INFINITE);
while (tick++ < COUNT)
{
g_x++;
}
ReleaseMutex(hMutex);
return 0;
}