Skip to content

Latest commit

 

History

History
69 lines (41 loc) · 5.03 KB

method.md

File metadata and controls

69 lines (41 loc) · 5.03 KB

同步机制就是为了解决资源访问竞争产生问题的一种方法与手段

常见同步机制

原子操作

原子操作是由编译器来保证的,保证一个线程对数据的操作不会被其他线程打断。

自旋锁(spin lock)

当发生访问资源冲突的时候,当一个进程或线程获取了一个自旋锁后,另外一个进程或线程期望获取该自旋锁,获取不到,只能够原地“打转”(忙等待),这也是为啥叫自旋锁的原因。进程、线程、软中断和硬中断都可以使用自旋锁。由于自旋过程中是消耗CPU资源的,所以自旋锁不适用于自不应该被长时间的持有场景。

信号量(semaphore)

信号量(semaphore)是进程间通信处理同步互斥的机制。是在多线程环境下使用的一种措施,它负责协调各个进程,以保证他们能够正确、合理的使用公共资源。 它和spin lock最大的不同之处就是:无法获取信号量的进程可以睡眠,会产生导致系统调用。当semaphore的count值为1是,称为互斥信号量。

读写锁(read-write lock)

不管是自旋锁还是信号量在同一时间只能有一个进程进入临界区。对于有些情况,我们是可以区分读写操作的。因此,我们希望对于读操作的进程可以并发进行。对于写操作只限于一个进程进入临界区。而这种同步机制就是读写锁。读写锁一般具有以下几种性质:

  • 同一时间有且仅有一个写进程进入临界区
  • 在没有写进程进入临界区的时候,同时可以有多个读进程进入临界区
  • 读进程和写进程不可以同时进入临界区

读写锁有两种,一种是信号量类型,另一种是spin lock类型。

互斥量(mutex)

semaphore在初始化count计数的时候,可以分为计数信号量和互斥信号量(二值信号量)。mutex和初始化计数为1的二值信号量有很大的相似之处。他们都可以用做资源互斥。但是mutex却有一个特殊的地方:只有持锁者才能解锁。但是二值信号量却可以在一个进程中获取信号量,在另一个进程中释放信号量。

Futex

Futex是Fast Userspace muTexes的缩写,它是一种用户态和内核态混合的同步机制。Futex中文翻译是快速用户空间互斥体。

Futex实现机制是同步的进程间通过mmap共享一段内存,futex变量就位于这段共享的内存中且操作是原子的,当进程尝试进入互斥区或者退出互斥区的时候,先去查看共享内存中的futex变量,如果没有竞争发生,则只修改futex,而不用再执行系统调用了。当通过访问futex变量告诉进程有竞争发生,则还是得执行系统调用去完成相应的处理(wait 或者 wake up)。简单的说,futex就是通过在用户态的检查,(motivation)如果了解到没有竞争就不用陷入内核了,大大提高了low-contention时候的效率。

Futex函数定义如下:

int futex (int *uaddr, int op, int val, const struct timespec *timeout,int *uaddr2, int val3)

  • uaddr就是用户态下共享内存的地址,里面存放的是一个对齐的整型计数器。
  • op存放着操作类型。常见操作类型有以下两个:
    • FUTEX_WAIT: 原子性的检查uaddr中计数器的值是否为val,如果是则让进程休眠,直到FUTEX_WAKE或者超时(time-out)。也就是把进程挂到uaddr相对应的等待队列上去。
    • FUTEX_WAKE: 最多唤醒val个等待在uaddr上进程

Futex使用流程:

  • 用户线程通过CAS类原子指令尝试获取锁,如果成功,则获取锁成功。这种情况下无需调用系统调用,不需要进入内核。开销很小。
  • 如果CAS失败,可以选择spin重试,也可以选择挂起自己等待唤醒。这里即调用系统调用,让内核操作挂起,为了保证锁原语,调用者将futex word的当前状态(锁定状态)作为参数传入内核,内核进行检查如果与futex word的当前一致,则挂起线程。否则返回失败。
  • 为了唤醒等待线程,获取锁的线程在释放锁后,需要调用系统调用,来通知锁释放,内核会唤醒等待者进行竞争锁。

总结

各种同步机制比较:

类型 机制 适用场景
原子操作 数据的原子访问 使用于简单的数据类型,比如整形
自旋锁 未获取锁时候,忙等待,进程不挂起 1. 适用于多处理器间共享数据
2. 在可抢占的内核线程里共享数据
3. 适用锁保持时间很短的情况
4. 可以使用任何上下文中使用比如中断上下文
信号量 阻塞式等待,进程挂起 1. 适合共享区保持时间较长的情况
2. 只适用于进程上下文
rwlock 特殊的自旋锁 1. 允许同事读共享资源,但只能有一个写
2. 读优先于写, 读写不能同时进行

同步机制如何选择:

资料

Linux内核中各种同步机制