
1) 【一句话结论】在Windows多线程开发中,处理共享资源竞争的核心是通过同步机制(如互斥锁、临界区等)确保同一时间仅有一个线程访问共享资源,避免数据不一致或竞争条件,需根据场景选择合适工具并注意避免死锁。
2) 【原理/概念讲解】共享资源竞争是指多个线程同时访问同一共享资源(如全局变量、文件句柄、内存块等)时,若不加以控制,可能导致数据损坏或逻辑错误。同步机制的作用是提供互斥访问(即“互斥”原则),确保同一时间只有一个线程操作共享资源。类比:共享教室的钥匙,只有一把钥匙,进入教室后锁上,其他线程等待,直到当前线程离开(释放锁)。
3) 【对比与适用场景】
| 同步机制 | 定义 | 特性 | 适用场景 | 注意点 |
|---|---|---|---|---|
| 互斥锁(Mutex) | 线程间互斥访问资源的对象,确保同一时间只有一个线程持有锁 | 互斥、可重入(部分)、阻塞等待 | 保护关键代码段(如修改全局变量、文件操作) | 需确保锁被正确释放,避免死锁 |
| 临界区(Critical Section) | Windows提供的轻量级互斥机制,适用于同一进程内线程间同步 | 简单、效率高,仅限同一进程 | 保护短时间访问的共享资源(如读取/写入小数据) | 不支持跨进程,线程数过多可能效率低 |
| 信号量(Semaphore) | 控制多个线程对共享资源的访问数量(如允许N个线程同时访问) | 计数、可跨进程 | 限制并发线程数(如数据库连接池、资源池) | 需初始化正确,避免死锁 |
| 事件(Event) | 用于线程间通信,通知线程某个事件发生 | 通知机制,无互斥 | 等待某个条件满足(如任务完成、资源可用) | 需区分手动/自动重置,避免线程一直等待 |
4) 【示例】(伪代码,保护全局计数器)
int g_counter = 0;
CRITICAL_SECTION cs; // 临界区对象
InitializeCriticalSection(&cs); // 初始化
void ThreadFunc() {
for (int i = 0; i < 1000; ++i) {
EnterCriticalSection(&cs); // 获取锁
g_counter++; // 临界区代码
LeaveCriticalSection(&cs); // 释放锁
}
}
int main() {
HANDLE hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFunc, NULL, 0, NULL);
HANDLE hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFunc, NULL, 0, NULL);
WaitForSingleObject(hThread1, INFINITE);
WaitForSingleObject(hThread2, INFINITE);
DeleteCriticalSection(&cs); // 释放临界区资源
printf("最终计数: %d\n", g_counter); // 理论应为2000,实际因同步正确
}
5) 【面试口播版答案】(约90秒)
“面试官您好,处理Windows多线程下的共享资源竞争,核心是通过同步机制确保互斥访问,避免数据竞争。比如,当多个线程同时修改全局变量时,需要用互斥锁(Mutex)或临界区(Critical Section)保护。以互斥锁为例,它相当于一把锁,同一时间只有一个线程能进入临界区(比如修改变量),其他线程等待。比如保护一个计数器,多个线程递增,用互斥锁确保每次只有一线程执行加法,最终结果正确。不同机制适用不同场景:临界区适合同一进程内短代码段,互斥锁更通用,信号量用于控制并发数量。关键是要正确初始化和释放锁,避免死锁。总结来说,选择合适的同步工具,正确使用,就能有效解决共享资源竞争问题。”
6) 【追问清单】
7) 【常见坑/雷区】