程序执行结果依赖于不同线程执行的先后顺序,那么就会形成「竞争条件」,由于竞争条件下计算结果是非预期的,因此我们应该尽量避免竞争条件的形成。
解决竞争条件的方式,除原子操作外,还有线程同步。
同步 && 互斥
多个线程之间协调同步,按照预定的先后次序进行运行(非同时)
对于线程共享的线程资源,在各个线程访问时具有排它性。当有若干个线程要访问同一共享资源时,任何时刻只允许一个线程进行访问,直到占有资源者放弃使用该资源。
同步方式
互斥锁
每个线程在对共享资源操作前都会尝试先加锁,加锁成功才能操作,操作结束之后解锁。
特点
- 当线程抢互斥锁失败的时候,线程会陷入休眠。
- 节省CPU资源,消耗等待时间
条件变量
条件变量用来锁定一个线程,直到某个特殊的条件发生才继续执行。
流程
- 创建条件变量
- 某线程因等待条件变量成立而挂起
- 一段时间后,另一个线程激活了条件变量
- 条件变量清楚,线程继续执行。
信号量
信号量,分匿名信号量和命名信号量。
临界资源 — 同一时刻只允许一个线程(或进程)访问的资源
临界区 — 访问临界资源的代码段。
P操作 — 申请资源
V操作 — 释放资源
信号量允许多个线程同时进入临界区,而互斥量只允许一个线程进入临界区。
读写锁
读写锁和互斥锁类似,但允许更高的并行性,有一定的性能提升。
一次只有一个线程可以占有写模式下的读写锁,但是可以有多个线程占有读模式下的读写锁。
- 写独占 — 写锁占用时,其他线程加读锁或者写锁时都会阻塞(并非失败)
- 读共享 — 读锁占用时,其他线程加写锁时会阻塞,加读锁会成功