linux4种锁

本文介绍了Linux内核中用于并发控制的关键技术,包括原子操作、自旋锁、读写自旋锁、顺序锁、信号量和互斥锁。原子操作提供对整型变量的无锁更新,自旋锁适用于短暂的临界区,防止资源竞争。读写自旋锁允许多个读取者并发访问,顺序锁则在读写之间提供了一定的并发性。信号量和互斥锁则允许线程在无法获取资源时进入休眠状态,确保资源的有序访问。这些机制在内核开发和多线程编程中至关重要。
摘要由CSDN通过智能技术生成

正点原子教程笔记

原子锁

typedef struct {
    int counter;
} atomic_t;

定义的两种方式:

atomic_t a; //定义 a

atomic_t b = ATOMIC_INIT(0); //定义原子变量 b 并赋初值为 0

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8UPfTyjV-1623029967557)(https://i.loli.net/2021/02/01/gfAYOn1VBXv2ioW.png)]

原子锁的使用如下所示:

atomic_t v = ATOMIC_INIT(0); /* 定义并初始化原子变零 v=0 */
atomic_set(10); /* 设置 v=10 */
atomic_read(&v); /* 读取 v 的值,肯定是 10 */
atomic_inc(&v); /* v 的值加 1,v=11 */

64位的原子锁

typedef struct {
 long long counter; 
} atomic64_t;

函数与上面相同 替换为atomic64_

原子操作只能对整形变量或者位进行保护

原子位操作

原子位操作是直接对内存进行操作

自旋锁

  1. 自旋锁会自动禁止抢占,因此保护区间不允许有休眠的函数,如果其他线程使用了该锁,就会发生死锁,因为该线程休眠完之后,抢占不到CPU。

  2. 获取锁之前关闭本地中断,如果中断当中获取该锁,也会发生死锁。

typedef struct spinlock {
    union {
    struct raw_spinlock rlock;
    #ifdef CONFIG_DEBUG_LOCK_ALLOC
    # define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
    struct {
        u8 __padding[LOCK_PADSIZE];
        struct lockdep_map dep_map;
        };
    #endif
    };
} spinlock_t;

自旋锁使用示例:

DEFINE_SPINLOCK(lock) /* 定义并初始化一个锁 */

/* 线程 A */
void functionA (){
    unsigned long flags; /* 中断状态 */
    spin_lock_irqsave(&lock, flags) /* 获取锁 */
    /* 临界区 */
    spin_unlock_irqrestore(&lock, flags) /* 释放锁 */
}

    /* 中断服务函数 */
void irq() {
    spin_lock(&lock) /* 获取锁 */
    /* 临界区 */
    spin_unlock(&lock) /* 释放锁 */
}

在自旋锁的基础上还衍生出了其他特定场合使用的锁

读写自旋锁

为读和写操作提供了不同的锁,一次只能允许一个写操作,也就是只能一个线
程持有写锁,而且不能进行读操作。但是当没有写操作的时候允许一个或多个线程持有读锁,可以进行并发的读操作

typedef struct {
 arch_rwlock_t raw_lock; 
} rwlock_t;


顺序锁

在读写锁的基础上衍生而来,实现同时读写,但是不允许同时进行并发的写操作。

typedef struct {
    struct seqcount seqcount;
    spinlock_t lock; 
} seqlock_t;

信号量

信号量可以使线程进入休眠状态

struct semaphore {
 raw_spinlock_t lock;
 unsigned int count;
 struct list_head wait_list;
};

信号量的使用如下所示:

struct semaphore sem; /* 定义信号量 */
sema_init(&sem, 1); /* 初始化信号量 */
down(&sem); /* 申请信号量 */
/* 临界区 */
up(&sem); /* 释放信号量 */

互斥锁

将信号量的值设置为 1 就可以使用信号量进行互斥访问了,互斥体—mutex更为专业。

struct mutex {
 /* 1: unlocked, 0: locked, negative: locked, possible waiters */
 atomic_t count;
 spinlock_t wait_lock;
};

互斥体的使用如下所示:

struct mutex lock; /* 定义一个互斥体 */
mutex_init(&lock); /* 初始化互斥体 */
mutex_lock(&lock); /* 上锁 */
/* 临界区 */
mutex_unlock(&lock); /* 解锁 */

Linux 内核还有很多其他的处理并发和竞争的机制,后续再学习。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值