Linux自旋锁和读写锁

        在前面的文章中我们已经介绍了有关互斥锁的概念与使用,本篇将开始介绍在 Linux 中的自旋锁和读写锁。这三种锁分别用于在不同的应用场景之中,其中互斥锁最为常用,但是我们需要了解一下其他的锁。

        对于自旋锁和读写锁都介绍了其原理以及接口使用,并且给出了样例代码。

目录

自旋锁

1. 自选锁概念和原理

2. 自旋锁的优缺点与接口使用

3. 自旋锁使用样例代码

读写锁

1. 读者写者模型 vs 生产消费模型

2. 读写锁伪代码和读写锁函数接口

3. 读者优先和写者有限

4. 读写锁使用样例代码

自旋锁

        在使用互斥锁对我们的临界资源上锁时,当其他线程抢不到锁,则会在系统调用中阻塞起来(操作系统将线程的 tcb 放入到等待队列中),等到抢到锁之后又会将线程唤醒(将线程的 tcb 从等待队列中放入到运行队列中)。但是假若在临界区运行的时间还没有将线程挂起等待的时间长,那么还不如让线程不断的轮询访问我们的锁,不将线程挂起等待,当锁一但释放就可以立即的获取到锁。

        自旋锁的应用中应用层中使用的非常少,但是在操作系统层面使用得很多,因为操作系统不会轻易的将自己挂起等待,所以对于某些资源需要等到访问的时候,通常都是轮询等待。

1. 自选锁概念和原理

        自旋锁概念:一种多线程同步机制,用于保护共享资源免受并发访问的影响。在多个线程尝试获取到锁时,它们会持续旋转(在循环中不断的检查锁是否可用)而不是立即进入休眠状态等待锁的释放。这种机制减少了线程切换的开销(因为假若是阻塞等待则会将线程挂起然后切换,而轮询则是在时间片内一直访问),适用于短时间内锁竞争的情况。但是假若不合理的使用(在临界区的运行时间较长),则会导致 CPU 的浪费。

        原理:自旋锁通常使用一个共享的标志位来表示锁的状态。当标志位为 true 时,表示锁已被某个线程占用;当标志位为 false 的时候,表示锁可用。当一个线程尝试获取自旋锁的时候,会不断的检查标志位。:

        1. 若标志位为 false,表示锁可以使用,线程将标志位设置为 true,表示占用了锁,然后进入到临界区中执行代码;        

        2. 若标志位为 true,表示锁已经被其他先占用,线程会在一个循环中不断自旋等待,直到锁被释放。

        对于自旋锁代码实现的伪代码如下:

typedef _Atomic struct
{
#if __GCC_ATOMIC_TEST_AND_SET_TRUEVAL == 1
_Bool __val;
#else
unsigned char __val;
#endif
} atomic_flag;

// ATOMIC_FLAG_INIT 值为0
atomic_flag spinlock = ATOMIC_FLAG_INIT;

// 尝试获取锁
void spinlock_lock() {
    // 没有获取到锁则一直运行,返回值为true
    // 获取到锁,返回值为false,跳出循环等待
    while (atomic_flag_test_and_set(&spinlock)) {
    // 如果锁被占用,则忙等待
    }
}

// 释放锁
void spinlock_unlock() {
    atomic_flag_clear(&spinlock);
}

atomic_flag_test_and_set 函数检查 atomic_flag 的当前状态。如果
atomic_flag 之前没有被设置过(即其值为 false 或“未设置”状态),则函数会将其
设置为 true(或“设置”状态),并返回先前的值(在这种情况下为 false)。如果
atomic_flag 之前已经被设置过(即其值为 true),则函数不会改变其状态,但会
返回 true。

        对于以上伪代码的实现,特别是对 atomic_flag 的操作一定得是原子的,这样才能保证 atomic_flag 的读取和修改在多线程环境中是不可分割的,同时这样保证了线程安全的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值