同步对象API
概述
在多线程编程中,同步对象用于协调多个线程对共享资源的访问,防止竞争条件和数据不一致。Windows提供了多种同步机制。
同步对象类型
- 临界区(Critical Section):最快,只能用于同一进程内的线程同步
- 互斥体(Mutex):可用于不同进程间的线程同步
- 信号量(Semaphore):控制对有限资源的并发访问数量
- 事件(Event):用于线程间的通知和等待
- 可等待定时器(Waitable Timer):定时通知
同步对象比较
| 对象 |
跨进程 |
开销 |
适用场景 |
| 临界区 |
否 |
最低 |
同进程内的高速同步 |
| 互斥体 |
是 |
中等 |
跨进程互斥访问 |
| 信号量 |
是 |
中等 |
资源计数控制 |
| 事件 |
是 |
中等 |
条件等待和通知 |
临界区对象
InitializeCriticalSection
| C++ |
|---|
| void InitializeCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
|
示例:
| C++ |
|---|
| CRITICAL_SECTION cs;
InitializeCriticalSection(&cs);
|
InitializeCriticalSectionAndSpinCount
| C++ |
|---|
| BOOL InitializeCriticalSectionAndSpinCount(
LPCRITICAL_SECTION lpCriticalSection,
DWORD dwSpinCount
);
|
参数:
- dwSpinCount:旋转计数,在阻塞前尝试获取锁的次数
SetCriticalSectionSpinCount
| C++ |
|---|
| DWORD SetCriticalSectionSpinCount(
LPCRITICAL_SECTION lpCriticalSection,
DWORD dwSpinCount
);
|
EnterCriticalSection
| C++ |
|---|
| void EnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
|
EnterCriticalSection
进入临界区。如果临界区已被其他线程占用,调用线程将阻塞等待。
示例:
| C++ |
|---|
| EnterCriticalSection(&cs);
// 临界区代码
LeaveCriticalSection(&cs);
|
TryEnterCriticalSection
| C++ |
|---|
| BOOL TryEnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
|
返回值:
- 非零:成功进入
- 零:临界区已被占用
示例:
| C++ |
|---|
| if (TryEnterCriticalSection(&cs)) {
// 成功进入临界区
// ...
LeaveCriticalSection(&cs);
} else {
// 临界区被占用,执行其他操作
}
|
LeaveCriticalSection
| C++ |
|---|
| void LeaveCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
|
DeleteCriticalSection
| C++ |
|---|
| void DeleteCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
|
完整示例
| C++ |
|---|
| #include <windows.h>
#include <stdio.h>
CRITICAL_SECTION g_cs;
int g_counter = 0;
DWORD WINAPI ThreadFunc(LPVOID param) {
for (int i = 0; i < 10000; i++) {
EnterCriticalSection(&g_cs);
g_counter++;
LeaveCriticalSection(&g_cs);
}
return 0;
}
int main() {
InitializeCriticalSection(&g_cs);
HANDLE threads[10];
for (int i = 0; i < 10; i++) {
threads[i] = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL);
}
WaitForMultipleObjects(10, threads, TRUE, INFINITE);
printf("Counter: %d\n", g_counter);
DeleteCriticalSection(&g_cs);
for (int i = 0; i < 10; i++) {
CloseHandle(threads[i]);
}
return 0;
}
|
互斥体对象
CreateMutex
| C++ |
|---|
| HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,
BOOL bInitialOwner,
LPCTSTR lpName
);
|
参数:
- lpMutexAttributes:安全属性
- bInitialOwner:调用线程是否初始拥有互斥体
- lpName:互斥体名称(用于跨进程)
示例:
| C++ |
|---|
| HANDLE hMutex = CreateMutex(NULL, FALSE, L"MyMutex");
if (hMutex == NULL) {
printf("CreateMutex failed: %d\n", GetLastError());
}
|
OpenMutex
| C++ |
|---|
| HANDLE OpenMutex(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);
|
ReleaseMutex
| C++ |
|---|
| BOOL ReleaseMutex(
HANDLE hMutex
);
|
跨进程互斥示例
| C++ |
|---|
| // 进程1:创建互斥体
#include <windows.h>
#include <stdio.h>
int main() {
HANDLE hMutex = CreateMutex(NULL, FALSE, L"Global\\MyMutex");
printf("Waiting for mutex...\n");
WaitForSingleObject(hMutex, INFINITE);
printf("Got mutex, working...\n");
Sleep(5000); // 模拟工作
ReleaseMutex(hMutex);
CloseHandle(hMutex);
return 0;
}
|
| C++ |
|---|
| // 进程2:打开互斥体
#include <windows.h>
#include <stdio.h>
int main() {
HANDLE hMutex = OpenMutex(SYNCHRONIZE, FALSE, L"Global\\MyMutex");
if (hMutex == NULL) {
printf("OpenMutex failed: %d\n", GetLastError());
return -1;
}
printf("Waiting for mutex...\n");
WaitForSingleObject(hMutex, INFINITE);
printf("Got mutex, working...\n");
ReleaseMutex(hMutex);
CloseHandle(hMutex);
return 0;
}
|
信号量对象
CreateSemaphore
| C++ |
|---|
| HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount,
LONG lMaximumCount,
LPCTSTR lpName
);
|
参数:
- lInitialCount:初始计数
- lMaximumCount:最大计数
示例:
| C++ |
|---|
| // 创建信号量:最多3个线程同时访问
HANDLE hSem = CreateSemaphore(NULL, 3, 3, NULL);
|
OpenSemaphore
| C++ |
|---|
| HANDLE OpenSemaphore(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);
|
ReleaseSemaphore
| C++ |
|---|
| BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
LPLONG lpPreviousCount
);
|
示例:
| C++ |
|---|
| LONG prevCount;
ReleaseSemaphore(hSem, 1, &prevCount); // 释放1个资源
|
连接池示例
| C++ |
|---|
| #include <windows.h>
#include <stdio.h>
HANDLE hSemaphore;
CRITICAL_SECTION cs;
DWORD WINAPI WorkerThread(LPVOID param) {
int id = (int)(LONG_PTR)param;
printf("Thread %d: Waiting for connection...\n", id);
WaitForSingleObject(hSemaphore, INFINITE);
printf("Thread %d: Got connection, working...\n", id);
Sleep(2000); // 模拟工作
printf("Thread %d: Releasing connection...\n", id);
ReleaseSemaphore(hSemaphore, 1, NULL);
return 0;
}
int main() {
// 创建信号量:最多3个连接
hSemaphore = CreateSemaphore(NULL, 3, 3, NULL);
InitializeCriticalSection(&cs);
// 创建10个工作线程
HANDLE threads[10];
for (int i = 0; i < 10; i++) {
threads[i] = CreateThread(NULL, 0, WorkerThread, (LPVOID)(LONG_PTR)i, 0, NULL);
}
WaitForMultipleObjects(10, threads, TRUE, INFINITE);
DeleteCriticalSection(&cs);
CloseHandle(hSemaphore);
for (int i = 0; i < 10; i++) {
CloseHandle(threads[i]);
}
return 0;
}
|
事件对象
CreateEvent
| C++ |
|---|
| HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCTSTR lpName
);
|
参数:
- bManualReset:
- TRUE:手动重置事件
- FALSE:自动重置事件
- bInitialState:初始状态
手动重置 vs 自动重置:
| 类型 |
SetEvent后 |
适用场景 |
| 手动重置 |
一直保持触发,需手动ResetEvent |
唤醒多个等待线程 |
| 自动重置 |
唤醒一个线程后自动重置 |
唤醒单个等待线程 |
OpenEvent
| C++ |
|---|
| HANDLE OpenEvent(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);
|
SetEvent
| C++ |
|---|
| BOOL SetEvent(
HANDLE hEvent
);
|
ResetEvent
| C++ |
|---|
| BOOL ResetEvent(
HANDLE hEvent
);
|
PulseEvent
| C++ |
|---|
| BOOL PulseEvent(
HANDLE hEvent
);
|
PulseEvent
设置事件后立即重置。不推荐使用,可能丢失信号。
生产者-消费者示例
| C++ |
|---|
| #include <windows.h>
#include <stdio.h>
#include <queue>
const int BUFFER_SIZE = 5;
std::queue<int> buffer;
CRITICAL_SECTION cs;
HANDLE hProducerEvent; // 生产者事件
HANDLE hConsumerEvent; // 消费者事件
DWORD WINAPI Producer(LPVOID param) {
for (int i = 1; i <= 20; i++) {
EnterCriticalSection(&cs);
while (buffer.size() >= BUFFER_SIZE) {
LeaveCriticalSection(&cs);
WaitForSingleObject(hProducerEvent, INFINITE);
EnterCriticalSection(&cs);
}
buffer.push(i);
printf("Produced: %d (size: %zu)\n", i, buffer.size());
SetEvent(hConsumerEvent); // 通知消费者
LeaveCriticalSection(&cs);
Sleep(100);
}
// 结束信号
EnterCriticalSection(&cs);
buffer.push(-1); // 特殊标记
SetEvent(hConsumerEvent);
LeaveCriticalSection(&cs);
return 0;
}
DWORD WINAPI Consumer(LPVOID param) {
while (true) {
EnterCriticalSection(&cs);
while (buffer.empty()) {
LeaveCriticalSection(&cs);
WaitForSingleObject(hConsumerEvent, INFINITE);
EnterCriticalSection(&cs);
}
int item = buffer.front();
buffer.pop();
if (item == -1) {
LeaveCriticalSection(&cs);
break;
}
printf("Consumed: %d (size: %zu)\n", item, buffer.size());
SetEvent(hProducerEvent); // 通知生产者
LeaveCriticalSection(&cs);
Sleep(150);
}
return 0;
}
int main() {
InitializeCriticalSection(&cs);
hProducerEvent = CreateEvent(NULL, FALSE, TRUE, NULL); // 自动重置,初始有信号
hConsumerEvent = CreateEvent(NULL, FALSE, FALSE, NULL); // 自动重置,初始无信号
HANDLE hProducer = CreateThread(NULL, 0, Producer, NULL, 0, NULL);
HANDLE hConsumer = CreateThread(NULL, 0, Consumer, NULL, 0, NULL);
WaitForSingleObject(hProducer, INFINITE);
WaitForSingleObject(hConsumer, INFINITE);
CloseHandle(hProducer);
CloseHandle(hConsumer);
CloseHandle(hProducerEvent);
CloseHandle(hConsumerEvent);
DeleteCriticalSection(&cs);
return 0;
}
|
可等待定时器
CreateWaitableTimer
| C++ |
|---|
| HANDLE CreateWaitableTimer(
LPSECURITY_ATTRIBUTES lpTimerAttributes,
BOOL bManualReset,
LPCTSTR lpTimerName
);
|
SetWaitableTimer
| C++ |
|---|
| BOOL SetWaitableTimer(
HANDLE hTimer,
const LARGE_INTEGER *lpDueTime,
LONG lPeriod,
PTIMERAPCROUTINE pfnCompletionRoutine,
LPVOID lpArgToCompletionRoutine,
BOOL fResume
);
|
示例:
| C++ |
|---|
| #include <windows.h>
#include <stdio.h>
int main() {
HANDLE hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
// 设置定时器:1秒后触发,每2秒一次
LARGE_INTEGER dueTime;
dueTime.QuadPart = -10000000LL; // 1秒(单位:100纳秒)
SetWaitableTimer(hTimer, &dueTime, 2000, NULL, NULL, FALSE);
for (int i = 0; i < 5; i++) {
WaitForSingleObject(hTimer, INFINITE);
printf("Timer triggered: %d\n", i + 1);
}
CancelWaitableTimer(hTimer);
CloseHandle(hTimer);
return 0;
}
|
CancelWaitableTimer
| C++ |
|---|
| BOOL CancelWaitableTimer(
HANDLE hTimer
);
|
互锁变量操作
原子操作,不需要额外同步。
InterlockedIncrement
| C++ |
|---|
| LONG InterlockedIncrement(
LONG *Addend
);
|
InterlockedDecrement
| C++ |
|---|
| LONG InterlockedDecrement(
LONG *Addend
);
|
InterlockedExchange
| C++ |
|---|
| LONG InterlockedExchange(
LONG *Target,
LONG Value
);
|
InterlockedCompareExchange
| C++ |
|---|
| LONG InterlockedCompareExchange(
LONG *Destination,
LONG Exchange,
LONG Comparand
);
|
示例:
| C++ |
|---|
| #include <windows.h>
#include <stdio.h>
LONG g_counter = 0;
DWORD WINAPI ThreadFunc(LPVOID param) {
for (int i = 0; i < 10000; i++) {
InterlockedIncrement(&g_counter);
}
return 0;
}
int main() {
HANDLE threads[10];
for (int i = 0; i < 10; i++) {
threads[i] = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL);
}
WaitForMultipleObjects(10, threads, TRUE, INFINITE);
printf("Counter: %d\n", g_counter);
for (int i = 0; i < 10; i++) {
CloseHandle(threads[i]);
}
return 0;
}
|
参考资料