【linux】常用的互斥手段及实例简述

文章目录

  • 10. 原子变量(atomic_t)
  • 20. 自旋锁(spinlock_t)
  • 21. 读写锁(rwlock_t)
  • 22. 顺序锁(seqlock_t)

10. 原子变量(atomic_t)

  1. 头文件
#include 
// -> 
// 		-> 
  1. 结构体
/* 32bit */
typedef LONG atomic_t;
#define LONG        .wordk
/* 64bit */
typedef struct {
    long long counter;
} atomic64_t;
  1. 实例
#ifdef _TEST_ATOMIC_32
    /* 32bit */
    int val_a = 0;
    atomic_t a = ATOMIC_INIT(0);// int a = 32;
    // set / read
    atomic_set(&a, 32);         // a = 100;
    val_a = atomic_read(&a);    // VAL = a;
    // add / sub
    atomic_add(1, &a);          // a = a + 1;
    atomic_sub(2, &a);          // a = a - 1;
    // inc / dec
    atomic_inc(&a);             // a++;
    atomic_dec(&a);             // a--;
#else
    /* 64bit */
    u64 val_b = 0;                      // unsigned long long val_b = 0;
    atomic64_t b = ATOMIC64_INIT(0);    // unsigned long long b = 0;
    // set / read
    atomic64_set(&b, 64);               // b = 64
    val_b = atomic64_read(&b);          // VAL = b;
    // add / sub
    atomic64_add(1, &b);                // b = b + 1;
    atomic64_sub(2, &b);                // b = b - 1;
    // inc / dec
    atomic64_inc(&b);                   // b++;
    atomic64_dec(&b);                   // b--;
#endif
  1. 备注
    32bit与64bit有两套接口,但是部分API是通用的,
    底层实现都是靠barrier(),
    不同长度的数据读取也可以靠类型转换来实现。

20. 自旋锁(spinlock_t)

  1. 头文件
#include          // for spinlock
  1. 结构体
typedef struct spinlock {
    union {
        struct raw_spinlock rlock;
    };
} spinlock_t;
  1. 实例
#include 

static DEFINE_SPINLOCK(vga_lock);		// init

    {
        unsigned long flags;
        spin_lock_irqsave(&test_spinlock, flags);
        {
            // do something
        }
        spin_unlock_irqrestore(&test_spinlock, flags);
    }
#if 0
    {/* in irq */
        spin_lock();
        spin_unlock();
    }
#endif
  1. 备注
  1. 临界代码中不要调用会引起系统调度的代码,即不要把cpu让出去
  2. 中断肯定会导致嵌套,而锁又不能做系统调度,两者量结合会导致死锁,所以需要屏蔽中断。
    2.1 调用_irqsave()、_irqrestore()做中断现场的保存和恢复
    2.2 中断中直接调用,不需要处理中断
  3. 头文件会有嵌套,这里的头文件只是最终的头文件,下面不再赘述

21. 读写锁(rwlock_t)

  1. 头文件
#include          // for rwlock
  1. 结构体
typedef struct {
    arch_rwlock_t raw_lock;
} rwlock_t;
  1. 实例
#include 

static DEFINE_RWLOCK(test_rwlock);		// init

    {
        unsigned long flags;

        /* read lock */
        read_lock_irqsave(&test_rwlock, flags);
        {
            // read something
        }
        read_unlock_irqrestore(&test_rwlock, flags);

        /* write lock */
        write_lock_irqsave(&test_rwlock, flags);
        {
            // write something
        }
        write_unlock_irqrestore(&test_rwlock, flags);
    }
  1. 备注
  1. 自旋锁解决了 读-读、读-写、写-写的竞态,但是读-读是可以并发的,所以引入了读写锁
  2. 与自旋锁在使用上的区别在于,定义了将读-写分成了两部分API,由程序员分类处理读写

22. 顺序锁(seqlock_t)

  1. 头文件
#include               // for seqlock
  1. 结构体
typedef struct {
    struct seqcount seqcount;
    spinlock_t lock;
} seqlock_t;
  1. 实例
#include 

static DEFINE_SEQLOCK(test_seqlock);	// init

    {
        unsigned long flags;

        /* read seqlock */
        {
            unsigned seq;
retry:
            seq = read_seqbegin(&test_seqlock);
            {
                // read something
            }
            if(read_seqretry(&test_seqlock, seq))
                goto retry;
        }

        /* write seqlock */
        write_seqlock_irqsave(&test_seqlock, flags);
        {
            // write something
        }
        write_sequnlock_irqrestore(&test_seqlock, flags);
    }
  1. 备注
  1. 顺序锁在读写锁的基础上,又允许了写-写的并发,其实现逻辑如下:
    1.1 写:获取锁,写操作,释放锁(写操作会修改序号,给读取函数来判断)
    1.2 读:先获取一个序号,读操作,判断之前的序号是否变化,如果变化了重新执行“获取-读取-判断”

你可能感兴趣的:(linux,spinlock,atomic)