C++多线程之旅实战-自旋锁那点事

本文介绍了自旋锁的概念,展示了C++实现自旋锁的方式,并讨论了其优缺点及适用场景。自旋锁在锁竞争不激烈、占用锁时间短的情况下能提高性能,但长时间占用会导致CPU浪费。文章还比较了Ticket Lock、CLH Lock和MCS Lock,分析了它们在公平性和性能上的差异。
摘要由CSDN通过智能技术生成

前言

前一篇文章讲的是带锁的并发数据结构,而且讲到了如果不带锁将会面临什么样的问题。这一部分我将为大家带来一个全新的数据结构-自旋锁。这是一种不使用阻塞库的数据结构,我们将不使用阻塞库的结构称为非阻塞,但是不是所有的非阻塞数据结构都是无锁的。

阻塞函数就是当这个函数不执行完,函数所在线程就一直停止在这里不动。

比如最常见的在多线程里面的thread库基本上都是阻塞函数。

实现

自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。

class spinlock {
   
    atomic_flag flag;
public:
    spinlock(): flag(ATOMIC_FLAG_INIT){
   }

    void lock() {
   
        while (flag.test_and_set(memory_order_acquire));
    }

    void unlock() {
   
        flag.clear(memory_order_release);
    }
};

spinlock sp;

void fun_1(){
   
    sp.lock();
    cout << "fun_1 is lock(); " << endl;
    sp.unlock();
    cout << "fun_1 is unlock();" << endl;
}

void fun_2() {
   
    sp.lock();
    cout << "fun_2 is lock(); " << endl;
    sp.unlock();
    cout << "fun_2 is unlock();" << endl;
}

int main() {
   
    thread t1(fun_1);
    thread t2(fun_2);
    t1.join();
    t2.join();
}

在这里面使用atomic实现了互斥锁的功能,虽然没有调用任何阻塞函数但是依然不是无锁数据结构。

所有的代码围绕着循环“旋转”,这也是自旋锁的由来。而且这样也会像使用阻塞函数一样,占用内存资源。

优缺点

缺点
  1. 如果某个线程持有锁的时间过长,就会导致其它等待获取锁的线程进入循环等待,消耗CPU。使用不当会造成CPU使用率极高。

  2. 上面C++实现的自旋锁不是公平的,即无法满足等待时间最长的线程优先获取锁。不公平的锁就会存在“线程饥饿”问题。

优点

自旋锁不会使线程状态发生切换,一直处于用户态,即线程一直都是active的;不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快。

非自旋锁在获取不到锁的时候会进入阻塞状态,从而进入内核态,当获取到锁的时候需要从内核态恢复,需要

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值