1. 为什么需要线程同步?
多线程编程中最让人头疼的问题莫过于数据竞争和线程间协调。想象一下,两个线程同时操作同一个银行账户,一个在取款,一个在查询余额,如果没有同步机制,查询结果很可能是不准确的。这就是为什么我们需要线程同步机制。
在Windows平台上,事件对象(Event Object)是一种非常实用的线程同步原语。它就像一个红绿灯,线程可以在这里等待"绿灯"信号。相比临界区(Critical Section)和互斥量(Mutex),事件对象更适合用于线程间的通知机制,特别是当需要多个线程等待某个条件满足时。
2. 事件对象的工作原理
2.1 事件对象的核心特性
Windows事件对象有两种类型:
- 手动重置事件(Manual-reset Event):需要手动调用ResetEvent来重置状态
- 自动重置事件(Auto-reset Event):当一个等待线程被释放后自动重置
事件对象有两种状态:
- 有信号状态(signaled):相当于绿灯,等待的线程可以继续执行
- 无信号状态(non-signaled):相当于红灯,线程会阻塞等待
2.2 相关API函数
主要的API函数包括:
cpp复制HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCTSTR lpName
);
BOOL SetEvent(HANDLE hEvent);
BOOL ResetEvent(HANDLE hEvent);
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
3. 实现线程同步的完整示例
3.1 场景设计
我们模拟一个典型的生产者-消费者场景:
- 生产者线程生成数据
- 消费者线程处理数据
- 使用事件对象来协调两者的工作节奏
3.2 完整实现代码
cpp复制#include <windows.h>
#include <iostream>
#include <vector>
#define DATA_SIZE 10
HANDLE hEvent;
std::vector<int> data;
DWORD WINAPI ProducerThread(LPVOID lpParam) {
for (int i = 0; i < DATA_SIZE; ++i) {
// 模拟数据生产耗时
Sleep(500);
data.push_back(i);
std::cout << "Produced: " << i << std::endl;
