【Windows编程】线程同步方式的比较
Windows 线程同步方式比较
1. 四种同步方式总览
Windows 线程同步的主要方式有四种:
| 同步方式 | 所属层级 | 跨进程支持 |
|---|---|---|
| 关键代码段(Critical Section) | 用户模式 | ❌ 不支持 |
| 互斥对象(Mutex) | 内核模式 | ✅ 支持 |
| 事件对象(Event) | 内核模式 | ✅ 支持 |
| 信号量(Semaphore) | 内核模式 | ✅ 支持 |
2. 选型建议
- 首选关键代码段:使用简单、效率高,适用于同一进程内多线程同步。在 MFC 程序中,可在类的构造函数中调用
InitializeCriticalSection,析构函数中调用DeleteCriticalSection,在需要保护的代码前后分别调用EnterCriticalSection和LeaveCriticalSection。 - 需要跨进程同步:使用互斥对象、事件对象或信号量(均为内核对象)。
- 需要限制并发访问数量:使用信号量(如限制同时访问某资源的线程数)。
3. 详细对比表
| 比较项 | 互斥量(Mutex) | 事件对象(Event) | 信号量(Semaphore) | 关键代码段(Critical Section) |
|---|---|---|---|---|
| 是否为内核对象 | 是 | 是 | 是 | 否 |
| 速度 | 较慢 | 较慢 | 较慢 | 快 |
| 跨进程同步 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ❌ 不支持 |
| 死锁风险 | 较低 | 较低 | 较低 | ⚠️ 较高(无法设超时) |
| 组成 | • 线程 ID(标识拥有者) • 计数器(递归次数) |
• 使用计数 • 重置类型(自动/人工) • 信号状态(有/无信号) |
• 使用计数 • 最大资源数 • 当前可用资源数 |
一段代码块,访问资源前需获得独占权 |
| 核心函数 | CreateMutexWaitForSingleObjectReleaseMutex |
CreateEventWaitForSingleObjectSetEventResetEvent |
CreateSemaphoreWaitForSingleObjectReleaseSemaphore |
InitializeCriticalSectionEnterCriticalSectionLeaveCriticalSectionDeleteCriticalSection |
| 注意事项 | 谁拥有谁释放;同一线程多次请求需对应多次 ReleaseMutex |
线程同步建议用自动重置(bManualReset = FALSE) |
允许多个线程同时访问,但需限制最大访问线程数 | 注意防止死锁(尤其使用多个临界区变量时) |
| 形象类比 | 一把钥匙(谁拿到谁独占) | 钥匙(自动重置=一次性钥匙,人工重置=门禁开关) | 停车场 + 保安(限制同时进入的车辆数) | 电话亭(一次只能一人进入) |
4. 关键代码段使用注意事项
| 注意事项 | 说明 |
|---|---|
| 配对调用 | 每次 EnterCriticalSection 必须对应一次 LeaveCriticalSection,否则其他等待线程将永远阻塞 |
| 死锁风险 | 使用多个临界区对象时,注意避免循环等待导致的死锁 |
| 无超时机制 | 等待进入关键代码段时无法设定超时值,容易造成线程永久阻塞 |
| 不可跨进程 | 仅限同一进程内的线程使用 |
5. 什么是线程安全?
线程安全:如果一段代码在多线程环境下执行的结果,与单线程环境下执行的结果完全一致,则该代码是线程安全的。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 星の夜!
