C++并发实战19:lock free编程

C++并发实战19:lock free编程涉及到并行/并发计算时,通常都会想到加锁,加锁可以保护共享的数据,不过也会存在一些问题:1.由于临界区无法并发运行,进入临界区就需要等待,加锁使得效率的降低。多核CPU也不能发挥全部马力2.在复杂的情况下,很容易造成死锁,并发进程、线程之间无止境的互相等待。3.在中断/信号处理函数中不能加锁,给并发处理带来困难。4.加锁影响实时性,等待时间不确定5.优先级反转,优先级

大家好,又见面了,我是你们的朋友全栈君。     涉及到并行/并发计算时,通常都会想到加锁,加锁可以保护共享的数据,不过也会存在一些问题:

1. 由于临界区无法并发运行,进入临界区就需要等待,加锁使得效率的降低。多核CPU也不能发挥全部马力

2. 在复杂的情况下,很容易造成死锁,并发进程、线程之间无止境的互相等待。

3. 在中断/信号处理函数中不能加锁,给并发处理带来困难。

4. 加锁影响实时性,等待时间不确定

5. 优先级反转,优先级高的等待优先级低的

6. 若一个线程带着锁挂了,那么将会影响其它等待该锁的线程

总之,在基于锁的多线程/多进程编程,你需要保证对竞争条件很敏感的共享数据上的任何操作,都通过加锁或解锁一个独占(mutex)来实现原子操作。

现有的加锁/无锁编程的种类如下:

     C++并发实战19:lock free编程

      其中标注为红色字体的方案为 Blocking synchronization需要锁,黑色字体为 Non-blocking synchronization无锁。Lock-based 和 Lockless-based 两者之间的区别仅仅是加锁粒度的不同。图中最底层的方案就是大家经常使用的 mutex 和 semaphore 等方案,代码复杂度低,但运行效率也最低。

      可以使用std::atomic实现lock free,但这里并不是真正的无锁,只有atomic_flag是无锁的,其它的atomic内部都是有锁的只不过粒度很小.atomic::compare_exchange_weak/strong等于是个CAS(比较并交换)操作,在C++11之前该操作是平台相关的,现在atomic将其实现为成员函数。

      一个lock free的栈:

#include <atomic>
#include <memory>

template<typename T>
class lock_free_stack//栈的底层数据结构采用单向链表实现
{
private:
    struct node
    {
        std::shared_ptr<T> data;//这里采用shared_ptr管理的好处在于:若栈内存放对象pop中return栈顶对象可能拷贝异常,栈内只存储指针还可以提高性能
        node* next;
        node(T const& data_):
            data(std::make_shared<T>(data_))//注意make_shared比直接shared_ptr构造的内存开销小
        {}
    };
    std::atomic<node*> head;//采用原子类型管理栈顶元素,主要利用atomic::compare_exchange_weak实现lock free
public:
    void push(T const& data)
    {
        node* const new_node=new node(data);
        new_node->next=head.load();//每次从链表头插入
        while(!head.compare_exchange_weak(new_node->next,new_node));//若head==new_node->next则更新head为new_node,返回true结束循环,插入成功; 若head!=new_node->next表明有其它线程在此期间对head操作了,将new_node->next更新为新的head,返回false,继续进入下一次while循环。这里采用atomic::compare_exchange_weak比atomic::compare_exchange_strong快,因为compare_exchange_weak可能在元素相等的时候返回false所以适合在循环中,而atomic::compare_exchange_strong保证了比较的正确性,不适合用于循环
    }
    std::shared_ptr<T> pop()
    {
        node* old_head=head.load();//拿住栈顶元素,但是可能后续被更新,更新发生在head!=old_head时
        while(old_head &&!head.compare_exchange_weak(old_head,old_head->next));//这里注意首先要先判断old_head是否为nullptr防止操作空链表,然后按照compare_exchange_weak语义更新链表头结点。若head==old_head则更新head为old_head->next并返回true,结束循环,删除栈顶元素成功;若head!=old_head表明在此期间有其它线程操作了head,因此更新old_head为新的head,返回false进入下一轮循环,直至删除成功。
        return old_head ? old_head->data : std::shared_ptr<T>();//这里注意空链表时返回的是一个空的shared_ptr对象
    }//这里只是lock free,由于while循环可能无限期循环不能在有限步骤内完成,故不是wait free
};

     

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/161734.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ubuntu开机出现initramfs解决办法[通俗易懂]

    ubuntu开机出现initramfs解决办法[通俗易懂]今天上班打开ubuntu的虚拟机的时候出现了这个界面:注意倒数第三行,说/dev/sda1需要fsck第一步:执行命令:fsck/dev/sda1-y第二步:当出现FILESYSTEMWASMODIFIED这个的时候,就表示已经成功了,然后输入reboot重启。注意:这次问题出现原因:虚拟机里给ubuntu关机以后,windows电脑强制关机造成,建议每次下班以后都完…

    2022年8月11日
    9
  • 【Android开发经验】使用Ant批量打包Android应用全然指南

    【Android开发经验】使用Ant批量打包Android应用全然指南

    2022年2月3日
    58
  • golang激活(在线激活)「建议收藏」

    golang激活(在线激活),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月14日
    64
  • c盘替换文件需要权限_windows安装命令

    c盘替换文件需要权限_windows安装命令大家都知道08权限的系统权限设置很严格,且在2003系统中常用到的溢出工具都失效。面对限制IP连接的情况我们及时拿到system权限有账号也上不去这种情况下只能弄shift后门或者放大镜了。但08权限在system权限也操作不了系统文件夹。先查通过whoami查看下登录帐号权限。通过下图我们看到是普通权限我用的到时MS12042这个大家都会用单独讲sysret.ex…

    2025年12月10日
    3
  • PyTorch安装最全流程

    PyTorch安装最全流程本文介绍基于Anaconda环境以及PyCharm软件结合,安装PyTorch深度学习框架。1.Anaconda安装下载链接:https://www.anaconda.com/1.1点击Next1.2点击同意1.3点击Next1.4选择目标文件夹,点击下一步1.5将Anaconda加入到系统变量安装成功后,在CMD中检查Anaconda时候加入到环境变量中。1.6单击启动AnacondaPrompt创建虚拟“房间”通过conda创建一个名为:pytorch.

    2022年6月24日
    73
  • Negative Sampling 负采样详解[通俗易懂]

    Negative Sampling 负采样详解[通俗易懂]在word2vec中,为了简化训练的过程,经常会用到NegativeSampling负采样这个技巧,这个负采样到底是怎么样的呢?之前在我的博文word2vec算法理解和数学推导中对于word2vec有了很详细的数学推导,这里主要讲解一下负采样是如何降低word2vec的复杂度的。首先我们直接写出word2vec的目标函数,假设有一句话:query=w1,w2,w3,..,wnquery=…

    2022年6月26日
    85

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号