关于 C++ 多线程编程一的些基本知识可以参考本博客的《C++11/14 新特性(多线程)》 ,《Unix线程基础》。本章不是多线程编程教程,而是个人经验的一些总结。这些经验有一些可能是不正确的,希望在今后的编程中实践、改进。
线程同步的四项基本原则:
- 最低限度地共享对象。对象尽量不要暴露给别的线程,如果需要暴露,优先考虑 immutable对象。否则尽量使用同步措施来充分地保护它
- 尽量使用高级地并发编程构件,如 任务队列、生产者消费者模式等
- 只用非递归的互斥器和条件变量,慎用读写锁,尽量少用信号量
- 除了使用
atomic
整数外,不要自己编写 lock-free 代码,也不要用"内核级"同步原语
互斥器 Mutex
mutex 是最常用的同步原语,它保护一个临界区,任何时候最多只能有一个线程能够访问 mutex 保护的域。使用 mutex 主要是为了保护共享数据。一般原则有:
- 使用
RAII
手法封装 mutex 的创建、销毁、加锁、解锁操作,充分保证锁的有效期等于其作用域,而不会因为中途返回或异常而忘记解锁。这类似于 Java 的synchronized
或 C# 的using
语句。 - 使用非递归的 mutex
- 尽量不要人为地调用
lock()
和unlock()
函数,将这些操作交给栈上的guard
对象,利用其构造与析构函数。 - 不要跨线程地加解锁,避免在不同的函数中分别加锁\解锁,避免在不同的语句分支中加锁\解锁
- 每当构造 guard 对象时,需要考虑栈上已有的锁,防止因加锁顺序不同而导致死锁
- 避免跨进程的 mutex, 进程间通讯尽量使用
TCP sockets