Linux 系统提供了五种用于线程间同步的方式:互斥锁、读写锁、自旋锁、信号量、条件变量
互斥锁
主要用于保护共享数据,确保同一时间内只有一个线程访问数据。
互斥量本质上来说就是一把锁,在访问共享资源前对互斥量进行加锁,访问完成后对释放互斥量,也就是解锁。
对互斥量进行加锁之后,任何其试图再次对互斥量加锁的线程都会被阻塞知道当前线程释放该互斥锁。
这样就能保证每次只有一个线程可以向前执行了。
读写锁
读写锁也叫做 共享互斥锁
他有三种状态:
读模式下加锁状态、写模式下加锁状态、不加锁状态。
一次只能有一个线程可以占有写模式的读写锁,但是多个线程可以同时占有读模式的读写锁。
因此与互斥量相比,读写锁允许更高的并行性。
读写锁非常适合对数据结构读的次数远大于写的情况。
自旋锁
自旋锁是一种忙等待锁,不是通过休眠使进程阻塞的,而是在获取锁之前一直处于忙等待(自旋)的阻塞状态。
自旋锁可用于以下情况:
锁被持有的时间短,而且线程并不希望在重新调度上花费太多的成本。
自旋锁用在非抢占式内核中时是非常有用的,除了提供互斥机制以外,还可以阻塞中断,这样中断处理程序就不会陷入死锁状态
信号量
线程的信号量和进程的信号量类似,使用线程的信号量可以高效地完成基于线程的资源计数。
信号量实际上是一个非负的整数计数器,用来实现对公共资源的控制。在访问前进行申请资源(P 操作)和在访问结束后进行释放资源(V 操作),以确保资源的正确使用
在公共资源增加的时候,信号量就增加;公共资源减少的时候,信号量就减少,只有当信号量大于 0 的时候,才能访问信号量所代表的公共资源。
条件变量
条件变量是线程可用的另一种同步机制。
条件变量给多个线程提供了一个会和的场所。
条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生,条件变量本身由互斥量保护。
线程在改变条件状态之前必须首先锁住互斥量。
其他线程在获得互斥量之前不会察觉到这种改变,因此互斥量必须在锁住以后才能计算条件。
总结
Linux 系统提供了五种用于线程间同步的方式:
互斥锁、读写锁、信号量、自旋锁、条件变量
- 互斥锁:用于保护共享变量,确保同一时间只有一个线程可以访问该资源,只有获得互斥锁的线程才能进入临界区,其他线程需要等待锁的释放
- 读写锁:也称为 共享-独占锁,允许多个线程同时读取共享资源,但在写操作时需要独占访问,读写锁在读多写少的场景中可以提供更好的并发性能。
- 信号量:用于控制对一组资源的访问。信号量允许多个线程同时访问资源,但是需要在访问前进行申请资源(P 操作)和在访问结束后进行释放资源(V 操作),以确保资源的正确使用
- 自旋锁:是一种忙等待锁,在获取锁之前,线程会一直尝试获取锁,而不会进入睡眠状态。自旋锁适用于锁占用时间短暂、保护临界区较小的情况
- 条件变量:用于在线程之间进行条件同步。一个线程可以等待某个条件满足,而另一个线程在满足条件时可以通知等待线程继续执行