并发编程(1): volatile、原子变量、自旋锁和互斥锁

并发编程三条特性: 

  • 原子性 原子性是指一个操作是不可中断的,要么全部执行成功要么全部执行失败。
  • 可见性 可见性是指当一个线程修改了共享变量后,其他线程能够立即看见这个修改。
  • 有序性 有序性是指程序指令按照预期的顺序执行而非乱序执行,乱序又分为编译器乱序和CPU执行乱序。

1 volatile变量

       volatile 变量不保证线程安全和不具备原子性的原因:在执行内存屏障之前,不同 CPU 依旧可以对同一个缓存行持有,一个 CPU 对同一个缓存行的修改不能让另一个 CPU 及时感知,因此出现并发冲突。线程安全还是需要用锁来保障,锁能有效的让 CPU 在同一个时刻独占某个缓存行,执行完并释放锁后,其他CPU才能访问该缓存行。

2 原子变量

       32位IA-32处理器使用基于对缓存加锁或总线加锁的方式来实现多处理器之间的原子操作。首先处理器会自动保证基本的内存操作的原子性。处理器保证从系统内存中读取或写入一个字节是原子的,意思是当一个处理器读取一个字节时,其他处理器不能访问这个字节的内存地址。两张锁机制如下:

  • 使用总线锁保证原子性 :总线锁就是使用处理器提供的一个LOCK#信号,当一个处理器在总线上输出此信号时,其他处理器的请求将被阻塞住,那么该处理器可以独占共享内存。
  • 使用缓存锁保证原子性 : 指内存区域如果被缓存在处理器的缓存行中,并且在Lock操作期间被锁定,那么当它执行锁操作回写到内存时,处理器不在总线上声言LOCK#信号,而是修改内部的内存地址,并允许它的缓存一致性机制来保证操作的原子性,因为缓存一致性机制会阻止同时修改由两个以上处理器缓存的内存区域数据,当其他处理器回写已被锁定的缓存行的数据时,会使缓存行无效。

对于gcc、g++编译器来讲,它们提供了一组API来做原子操作:

type __sync_fetch_and_add (type *ptr, type value, ...)
type __sync_fetch_and_sub (type *ptr, type value, ...)
type __sync_fetch_and_or (type *ptr, type value, ...)
type __sync_fetch_and_and (type *ptr, type value, ...)
type __sync_fetch_and_xor (type *ptr, type value, ...)
type __sync_fetch_and_nand (type *ptr, type value, ...)
bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)
type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)
type __sync_lock_test_and_set (type *ptr, type value, ...)
void __sync_lock_release (type *ptr, ...)

3 自旋锁

      底层是借助cpu的原子指令CAS实现的,自旋锁是采用忙等的状态获取锁,所以会一直占用cpu资源,但是允许不关闭中断的情况下。同时因为线程对cpu一直保持占用状态,所以对小资源加锁效率比较高,不需要做任何的线程切换,一般情况下如果加锁资源的运行延迟小于线程或者进程切换的时延则推荐使用自旋锁。如果需要等待耗时操作,则建议采用互斥锁。

//CAS操作在cpu指令集中可以是原子性的
int CompareAndExchange(int *ptr, int old, int new){
    int actual = *ptr;
    if (actual == old)
    *ptr = new;
    return actual;
}
void lock(lock_t *lock) {
     while (CompareAndExchange(&lock->flag, 0, 1) == 1); // spin
}
void unlock(lock_t *lock) {
     lock->flag = 0;
}

4 互斥锁

       互斥锁更多的是强调对共享资源的锁定作用,当一个线程占用了当前共享资源,使用互斥锁将其lock住之后,其他线程就无法访问,必须等到unlock之后,其他线程才能利用共享资源里面的内容;

  •  互斥锁是选择睡眠的方式来对共享工作停止访问的



 

你可能感兴趣的:(Linux笔记)