多线程同步
来源:互联网 发布:木门下单软件 编辑:程序博客网 时间:2024/06/03 23:40
读陈硕先生的《moduo多线程服务器编程》第二章线程同步精要,做下笔记。
编程概要
- 首要原则是尽量最低限度共享对象,减少需要同步的场合。
- 其次是使用高级的并发编程组件,如TaskQueue、Producer-Consumer Queue、CountDownLatch等. [链接](https://github.com/chenshuo/muduo)
- 最后不得已必须使用底层同步原语时,只用非递归的互斥器和条件变量,慎用读写锁,不要用信号量。
- 除了使用atomic整数之外,不自己写lock-free代码,也不要用“内核级”同步原语。
互斥器(mutex)
互斥器用于保护临界区,任何一个时刻最多只能有一个线程在此mutex划出的临界区内活动,单独使用mutex时,主要是为了保护共享资源。编程原则:
1. 用RAII手法封装mutex创建,销毁,加锁,解锁这四个操作。具体代码见最后。
2. 只用非递归的mutex(不可重入的mutex)。因为少用一个计数器,比递归的mutex略快一点,但主要还是为了设计意图,不是为了性能考虑。在同一个线程中多次对非递归mutex加入会立刻死锁,能帮助我们及早发现问题。
3. 不手工调用lock()和unlock()函数,一切交给栈上的Guard对象构造函数和析构函数负责。
4. 每次构造Guard对象,思考一路上(调用栈上)已经持有的锁,防止因加锁顺序不同而导致死锁。
次要原则:
1. 不使用跨进程的mutex,进程间通信只用TCP sockets。
2. 加锁、解锁都在同一个线程,线程a不能去unlock线程b已经锁住的mutex。
3. RAII保证解锁与不重复解锁。
4. 必要的时候可以考虑PTHREAD_MUTEX_ERRORCHECK来排错。
note: Linux的Pthreads mutex 采用 futex 实现,不必每次加锁、解锁都陷入内核。
条件变量(cond)
如果需要等待某个条件成立,应该使用条件变量,学名管程。
对于wait端:
1. 必须和mutex一起使用,该布尔表达式的读写需受此mutex保护。
2. 在mutex已上锁的时候才能调用wait()。
3. 把判断布尔条件和wait()放到while循环中。
例子1:
链接
例子2:
muduo::MutexLock mutex;muduo::Condition cond(mutex);std::deque<int> queue;int dequeue(){ MutexLockGuard lock(mutex); while(queue.empty()){ cond.wait(); } int top = queue.front(); queue.pop_front(); return pop;}
note:必须使用while循环来等待条件变量,不是使用if语句,原因是spurious wakeup。
对于signal/broadcast端:
1. 不一定要在mutex已上锁的情况下调用signal
2. 在signal之前一般要修改布尔表达式。
3. 修改布尔表达式通常要用mutex保护。
4. broadcast通常用于表明状态变化,signal通常用于表示资源可用。
例子1:
链接
例子2:
void enqueue(int x){ MutexLockGuard lock(mutex); queue.push_back(x); cond.notify();}
note:互斥器和条件变量构成了多线程编程的全部必备同步源于,用它们即可完成任何多线程同步任务,二者不可相互替代。
不用读写锁和信号量
- 正确性上:易发生在持有read lock时候修改了共享数据,这种错误的后果跟无保护并发读写共享数据时一样的。
- 性能上:读写锁不见得比普通mutex更高效,如果临界区很小,锁竞争不激烈,mutex往往更快。
- 通常reader lock是可重入的,writer lock是不可重入的。但为了防止writer饥饿,writer通常会阻塞后来的reader lock,因此reader lock在重入的时候可能死锁。
不用信号量:
1. 使用条件变量配合互斥器可以完全替代信号量,而且不易出错。
2. 信号量增加了程序设计的负担和出错的可能。
代码
MutexLock:
链接
MutextLockGuard:
链接
Condition:
链接
- 多线程同步
- 多线程同步
- 多线程同步
- 多线程同步
- 多线程同步
- 多线程同步
- 多线程同步
- 多线程同步
- 同步多线程
- 多线程同步
- 多线程同步
- 多线程、同步
- 多线程同步
- 多线程同步
- 多线程同步
- 多线程同步
- 多线程同步
- 多线程同步
- MODBUS TCP和MODBUS RTU的差别
- json前后端传输(ajax异步提交)
- 待补充
- Python数据分析常用手册——Numpy和Pandas
- ffmpeg 参数解析
- 多线程同步
- 组播地址规划
- CSS之创建等高列布局之三
- 操作系统相关面试题(1)
- Python super关键字
- SharedPreferences 判断APP是否第一次启动
- Scala入门到精通——第十六节 泛型与注解
- Android 动画
- win10 设置定时关机