windows的并发编程机制
- 内核
- 互斥(Mutex)
- 信号量(Semaphore)
- 自动重置事件(Auto-Reset Event)
- 手动重置事件(Manual-Reset Event)
- 等待定时器(Waitable Timer)
- 高级同步结构
- CRITICAL_SECTION: 使用一个Auto-Reset Event内核对象
- vista中的轻量级读写锁SRWL
VOID WINAPI InitializeSRWLock(PSRWLOCK SRWLock); //只需初始化,不需要delete
VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK SRWLock) //独占模式等待
VOID WINAPI AcquireSRWLockShared(PSRWLOCK SRWLock) //共享模式等待
VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK SRWLock) //独占模式释放
VOID WINAPI ReleaseSRWLockShared(PSRWLOCK SRWLock) //共享模式释放
- vista中的条件变量CONDITION_VARIABLE,相当于SignalObjectAndWait
BOOL WINAPI SleepConditionVariable{CS/SRW}
VOID WINAPI WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable)
VOID WINAPI WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable)
- 等待函数
- [Msg/Com]WaitForSingleObject[Ex]
- [Msg/Com]WaitForMultipleObjects[Ex]
- SignalObjectAndWait
其中Msg: GUI程序,Com: Com程序,当线程等待时仍可以分发消息
- 隐含的同步结构
- 键值事件(Keyed Event) : windows xp and above(hidden)
一个整个系统的全局事件,即等待线程的链表或hash表,存储了正在等待的事件的线程,不同互斥对象通过K来区分,通常为内存地址,键值事件已经是vista及以后系统中读写锁/条件变量的内部实现机制
注意事项:
- 在使用同步时优先选择高级同步结构如CRITICAL_SECTION/SRWL/CONDITION_VARIABLE,因为它们是在用户级实现的,可以相比于内核级的同步机制,减少内核切换,提高效率
- 对于运行时间很短的需要并发执行的程序可以利用线程池实现,而需要长时间运行的程序可以指定WT_TRANSFER_IMPERSONATION是线程池生成新的线程,或自己生成新线程并负责管理
- 使用线程池时,如果仅在vista及以上的系统上运行应尽量使用新的线程池api并尽可能采用SRWL/CONDITION_VARIABLE实现互斥与同步,如果考虑xp等的兼容性则应使用原api
- 编写并发程序时,应注意线程调度,缓存一致性等对性能的影响。注意不同细粒度对并发程序的影响,将伪并发(由于同步/互斥造成的线程排队运行的情况)修改为串行,减少不必要的开销。
- 可采用指定cpu运行的方式提高局部性
- 完成程序后最好测试一下并发与串行间的性能差异,选择更优的方案。
参考文献
- Joe Duffy. Windows并发编程指南[M]. 机械工业出版社. 2010
- Joe Duffy. Windows keyed events, critical sections, and new Vista synchronization features[OL]. http://www.bluebytesoftware.com/blog/PermaLink,guid,db9f8f5b-8d1d-44b0-afbd-3eadde24b678.aspx.