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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 简单选择排序 C语言

    简单选择排序 C语言简单选择排序(SimpleSelectionSort)也称作直接选择排序。算法步骤:1)设待排序的记录存放在数组Data[1…n]中。第一趟从Data[1]开始,通过n-1次比较,从n个记录中选出关键字最小的记录,记为Data[k],交换Data[1]和Data[k]。2)第二趟从Data[2]开始,通过n-2次比较,从n-1个记录中选出关键字最小的记录,记为Data[k],交换Data[2]和Data[k]。3)依次类推,第i趟从Data[i]开始,通过n-i次比较,从n-i

    2022年6月25日
    26
  • c语言code用法_visual code c语言

    c语言code用法_visual code c语言此文章出处:http://www.cppblog.com/izualzhy/archive/2012/07/09/182456.html先看个例子:汉字一的UTF-8编码为0xE40xb80x80我们在google里搜索一下“一”,地址栏显示为:可以看到url的字符串里有一个%E4%B8%80这就是encode之后的值。因此,encode的处理过程也很明显了。特别是传中文参数时,如果没…

    2022年9月28日
    3
  • intellij idea 19.4 激活码(破解版激活)

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

    2022年3月17日
    165
  • W3C标准及规范_地脚螺栓标准规范

    W3C标准及规范_地脚螺栓标准规范1.概念:W3C标准中文名:万维网联盟,外文名:WorldWideWebConsortium万维网联盟标准不是某一个标准,而是一些列标准的集合。网页主要有三部分组成:结构(Structure)、表现(Presentation)、行为(Behavior)。对应的标准也有三方面:结构化标准主要包括XHTML和XML,表现标准语言主要包括CSS、行为标准主要包括(如W3CDOM)、…

    2025年12月15日
    2
  • PHP编程效率的20个要点

    PHP编程效率的20个要点

    2021年10月9日
    41
  • centos7 apache 安装配置步骤[通俗易懂]

    centos7 apache 安装配置步骤[通俗易懂]1检查、删除、安装rpm-qa|grephttpd//检查是否安装apacherpm-e包名–nodeps//若有则删除PS:我没有删除,直接用的服务器原来的。yuminstallhttpd//安装,根据提示,输入Y即可安装成功2启动、测试systemctlstarthttpd//restart重启stop停止3查看 apache状…

    2025年12月5日
    5

发表回复

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

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