面试二十七、 CAS和Atomic

CAS锁机制(无锁、自旋锁、乐观锁、轻量级锁)-CSDN博客

1. ABA问题

在C++中,可以使用std::atomic和版本号来解决ABA问题。C++标准库没有直接提供类似Java的AtomicStampedReference,但可以通过将版本号和指针组合在一起实现类似的效果。

#include <atomic>
#include <iostream>
#include <thread>

template <typename T>
class AtomicStampedReference {
public:
    AtomicStampedReference(T initial_value, int initial_stamp)
        : value_(initial_value), stamp_(initial_stamp) {}

    bool compare_and_set(T expected_value, T new_value, int expected_stamp, int new_stamp) {
        auto current_value = value_.load();
        auto current_stamp = stamp_.load();
        return (current_value == expected_value && current_stamp == expected_stamp) &&
               value_.compare_exchange_strong(current_value, new_value) &&
               stamp_.compare_exchange_strong(current_stamp, new_stamp);
    }

    T get_reference() const {
        return value_.load();
    }

    int get_stamp() const {
        return stamp_.load();
    }

private:
    std::atomic<T> value_;
    std::atomic<int> stamp_;
};

void aba_example() {
    AtomicStampedReference<int> atomicStampedRef(100, 0);

    auto thread1 = [&atomicStampedRef]() {
        int stamp = atomicStampedRef.get_stamp();
        int reference = atomicStampedRef.get_reference();
        std::cout << "Thread 1 initial stamp: " << stamp << "\n";
        std::cout << "Thread 1 initial value: " << reference << "\n";
        if (atomicStampedRef.compare_and_set(reference, reference + 1, stamp, stamp + 1)) {
            std::cout << "Thread 1 new stamp: " << atomicStampedRef.get_stamp() << "\n";
            std::cout << "Thread 1 new value: " << atomicStampedRef.get_reference() << "\n";
        }
    };

    auto thread2 = [&atomicStampedRef]() {
        int stamp = atomicStampedRef.get_stamp();
        int reference = atomicStampedRef.get_reference();
        atomicStampedRef.compare_and_set(reference, reference + 1, stamp, stamp + 1);
        atomicStampedRef.compare_and_set(reference + 1, reference, stamp + 1, stamp + 2);
        std::cout << "Thread 2 stamp after ABA: " << atomicStampedRef.get_stamp() << "\n";
        std::cout << "Thread 2 value after ABA: " << atomicStampedRef.get_reference() << "\n";
    };

    std::thread t1(thread1);
    std::thread t2(thread2);

    t1.join();
    t2.join();
}

int main() {
    aba_example();
    return 0;
}

2. 自旋时间长开销大

循环时间长开销大

  • 描述:当多个线程竞争同一个CAS操作时,如果一直失败,线程会不断自旋重试,造成CPU资源的浪费。尤其在高并发情况下,频繁的CAS重试会导致较高的CPU开销。
  • 解决办法:可以使用自适应自旋锁或其他锁机制来减轻自旋的开销。

        自旋锁在高竞争情况下会导致大量CPU资源浪费。可以使用自适应自旋锁或结合其他锁机制来减轻这种开销。以下是一个简单的自适应自旋锁实现示例。

#include <atomic>
#include <thread>
#include <iostream>
#include <chrono>

class AdaptiveSpinLock {
public:
    AdaptiveSpinLock() : flag(ATOMIC_FLAG_INIT) {}

    void lock() {
        int spin_count = 0;
        while (flag.test_and_set(std::memory_order_acquire)) {
            ++spin_count;
            if (spin_count > max_spin_count) {
                std::this_thread::yield(); // 出让CPU
                spin_count = 0;
            }
        }
    }

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

private:
    static const int max_spin_count = 1000; // 自适应阈值
    std::atomic_flag flag;
};

void spinlock_example() {
    AdaptiveSpinLock lock;
    int counter = 0;

    auto increment = [&lock, &counter]() {
        for (int i = 0; i < 1000; ++i) {
            lock.lock();
            ++counter;
            lock.unlock();
        }
    };

    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Final counter value: " << counter << "\n";
}

int main() {
    spinlock_example();
    return 0;
}

3. 多变量原子操作

CAS只能保证单个变量的原子操作,要保证多个变量的原子操作,可以使用锁机制。以下是使用std::mutex来保证多个变量的原子操作的示例。

#include <mutex>
#include <thread>
#include <iostream>

class MultiVariable {
public:
    void update(int a, int b) {
        std::lock_guard<std::mutex> lock(mtx);
        var1 = a;
        var2 = b;
    }

    void get(int& a, int& b) {
        std::lock_guard<std::mutex> lock(mtx);
        a = var1;
        b = var2;
    }

private:
    int var1 = 0;
    int var2 = 0;
    std::mutex mtx;
};

void multivariable_example() {
    MultiVariable mv;

    auto writer = [&mv]() {
        for (int i = 0; i < 1000; ++i) {
            mv.update(i, i * 2);
        }
    };

    auto reader = [&mv]() {
        for (int i = 0; i < 1000; ++i) {
            int a, b;
            mv.get(a, b);
            std::cout << "Read values: " << a << ", " << b << "\n";
        }
    };

    std::thread t1(writer);
    std::thread t2(reader);

    t1.join();
    t2.join();
}

int main() {
    multivariable_example();
    return 0;
}

4.CAS使用注意事项
(1)CAS需要和volatile配合使用

CAS只能保证变量的原子性,不能保证变量的内存可见性。CAS获取共享变量的值时,需要和volatile配合使用,来保证共享变量的可见性

(2)CAS适用于并发量不高、多核CPU的情况

CPU多核情况下可以同时执行,如果不合适就失败。而并发量过高,会导致自旋重试耗费大量的CPU资源。

5. volatile

  • C++中的volatile:主要用于防止编译器优化,确保每次访问变量时从内存中读取最新的值,但不保证多线程环境下的内存可见性和顺序一致性。
  • 内存可见性:在C++中使用std::atomic和内存序列来确保多线程环境下的内存可见性和顺序一致性。

5.atomic

【超详解】C++原子变量atomic,全面解密!_c++ atomic-CSDN博客

atomic的底层实现 - 王的博客 - 博客园 (cnblogs.com)

CPU多核同步原语 - 知乎 (zhihu.com)

深入解析现代C++中的原子(std::atomic)-51CTO.COM

std::atomic通过硬件提供的原子指令实现无锁的原子操作,确保在多线程环境下的数据一致性和线程安全。通过使用内存顺序,可以进一步控制操作的可见性和顺序,以满足不同的并发编程需求。

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/668987.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

win系统游戏提示找不到d3dx9_37.dll丢失的解决方法-最简单的解决方法

d3dx9_37.dll 是一个动态链接库文件&#xff0c;属于 Microsoft DirectX 9 的一部分。DirectX 9 是一个用于多媒体应用&#xff0c;特别是游戏和视频的 API&#xff0c;它提供了一套丰富的功能&#xff0c;用于处理图形、声音和输入设备等。d3dx9_37.dll 文件包含了 Direct3D 9…

巨细巨细的白痴级vulntarget-a靶场wp再不会你打死我

ad一&#xff0c;靶场搭建 下载靶场&#xff1a;GitHub - crow821/vulntarget: vulntarget靶场系列 官方拓补图 ps&#xff1a;此处 攻击机ip192.168.87.134&#xff0c;win7ip1为192.168.87.144 下载完毕后直接装入虚拟机不要进去&#xff0c;不要进去&#xff0c;不要进去…

使用LLaMA-Factory微调大模型

使用LLaMA-Factory微调大模型 github 地址 https://github.com/hiyouga/LLaMA-Factory 搭建环境 git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Factory在 LLaMA-Factory 路径下 创建虚拟环境 conda create -p ./venv python3.10激活环境 c…

RabbiMQ怎么保证可靠性

RabbiMQ怎么保证可靠性 前言生产端问题解决方案代码验证 RabbitMQ问题消费端问题解决方案代码验证 总结 前言 RabbitMQ相信大家都非常熟悉了&#xff0c;今天咱们来聊聊怎么保证RabbitMQ的可靠性。 那什么时候会出现问题呢&#xff1f; 第一种是生产端出现的问题。我们向队列…

CTFHUB-信息泄露-目录遍历和PHPINFO

目录 目录遍历 PHPINFO 目录遍历 很简单&#xff0c;挨着把每个目录都点开看一下 发现2目录下有个 flag.txt 文件&#xff0c;点开发现了本关的flag PHPINFO 这关也很简单&#xff0c;进来之后是一个phpinfo页面&#xff0c;按 CTRL F键打开查询&#xff0c;输入flag&#…

成功解决“ypeError: An Integer Is Required”错误的全面指南

成功解决“ypeError: An Integer Is Required”错误的全面指南 &#x1f308; 欢迎莅临我的个人主页&#x1f448;这里是我深耕Python编程、机器学习和自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;并乐于分享知识与经验的小天地&#xff01;&#x1f387; &#x…

【科研基础】证明积累

1-Bayesian Estimation (P317) Suppose that x = θ + ν w h e r e ν i s a n N ( 0 , σ ) random variable and θ is the value of a n N ( θ 0 , σ 0 ) random variable θ (Fig. 8-7). Find the bayesian estimate θ o f θ . \begin{align…

神经网络与深度学习——第6章 循环神经网络

本文讨论的内容参考自《神经网络与深度学习》https://nndl.github.io/ 第6章 循环神经网络 给网络增加记忆能力 延时神经网络 有外部输入的非线性自回归模型 循环神经网络 简单循环网络 循环神经网络的计算能力 循环神经网络的通用近似定理 图灵完备 应用到机器学习 序列到类…

用贪心算法计算十进制数转二进制数(小数部分)

在上一篇博文用贪心算法计算十进制数转二进制数&#xff08;整数部分&#xff09;-CSDN博客中&#xff0c;小编介绍了用贪心算法进行十进制整数转化为二进制数的操作步骤&#xff0c;那么有朋友问我&#xff0c;那十进制小数转二进制&#xff0c;可以用贪心算法来计算吗&#x…

支付系统对接商户

target&#xff1a;离开柬埔寨倒计时-214day 还是美女作为开篇 前言 昨天没有写文章&#xff0c;因为部门团建&#xff0c;我得去给他们画饼&#xff0c;说起来也真的是唏嘘&#xff0c;我一个已经都在计划着离开柬埔寨的人&#xff0c;昨天聚餐还一个个给他们描述未来的前景&a…

5G无线标准演进综述及新技术引入

摘 要 随着经济和社会的发展&#xff0c;5G业务越来越丰富多彩&#xff0c;1080P高清视频、裸眼3D、网联汽车、云手机等新业务、新终端对网络的要求也越来越高&#xff1b;另一方面&#xff0c;5G标准持续演进&#xff0c;在MIMO、载波聚合、移动性管理、uRLLC、切片、定位等方…

海思SD3403,SS928/926,hi3519dv500,hi3516dv500移植yolov7,yolov8(19)-Yolov10探索

YOLOv10 开源有几天了,看性能是比较强的,但是试过的一些人说没有YOLOv8好,实际效果以测试结果为准,这里创新点算是去掉了之前YOLO的NMS步骤,论文题目也说了NMS-Free,以此来提高小目标检测率,减少计算冗余,也没有NMS的计算时间提高实时性。 这个倒是让我看到了以后可以…

以sqlilabs靶场为例,讲解SQL注入攻击原理【18-24关】

【less-18】 打开时&#xff0c;获取了自己的IP地址。&#xff0c;通过分析源码知道&#xff0c;会将用户的user-agent作为参数记录到数据库中。 提交的是信息有user-Agent、IP、uname信息。 此时可以借助Burp Suite 工具&#xff0c;修改user_agent&#xff0c;实现sql注入。…

STM32之USART(串口)通信学习

1.通信接口 在开始通信之前&#xff0c;我们要了解什么是通信&#xff0c;通信就是将一个设备的数据传送到另一个设备。 同时按照双方规定的协议即通信协议&#xff0c;指定通信规则通信双方按照规则进行数据的收发。 应用场景&#xff1a;单片机的串口可以使单片机与单片机…

软件架构设计属性之5:可维护性属性分析与应用

文章目录 引言一、可维护性定义和重要性1.1 定义1.2 重要性 二、可维护性关键要素2.1 模块化2.2 单一职责2.3 低耦合2.4 高内聚2.5 抽象和封装2.6 实践建议 三、设计原则3.1 开闭原则3.2 依赖倒置原则3.3 评估方法3.4 挑战与解决方案 四、实战应用总结 引言 在当今数字化飞速发…

利用GNSS IMU集成提高车道级定位精度

准确的定位对于很多不同的事情都是至关重要的。导航系统可以引导我们去某个地方&#xff0c;自动驾驶汽车可以利用这些数据在道路上安全行驶。尽管全球导航卫星系统(GNSS)在定位方面非常出色&#xff0c;但它们可能并不总是提供最准确的车道水平事实。解决这个问题的一个有希望…

大模型对齐方法笔记四:针对领域问答来进行知识对齐方法KnowPAT

KnowPAT KnowPAT(Knowledgeable Preference AlignmenT) 出自2023年11月的论文《Knowledgeable Preference Alignment for LLMs in Domain-specific Question Answering》&#xff0c;主要针对领域问答来进行知识对齐。 在领域问答有两个挑战&#xff1a;希望输出满足用户的要…

15-通过JS代码处理窗口滚动条

selenium并不是万能的&#xff0c;页面上有些操作无法实现时&#xff0c;就需要借助JS代码来完成了。selenium提供了一个方法&#xff1a;execute_script()&#xff0c;可以执行JS脚本代码。 比如&#xff1a;当页面上的元素超过一屏后&#xff0c;想操作屏幕下方的元素&#x…

git报错prohibited by Gerrit: not permitted: update

git push报错&#xff1a; Push to refs/for/[branch] to create a review, or get Push rights to update the branch. Contact an administrator to fix the permissions (prohibited by Gerrit: not permitted: update)原因&#xff1a; 使用Gerrit代码审核时&#xff0c;本…

IsoBench:多模态基础模型性能的基准测试与优化

随着多模态基础模型的快速发展&#xff0c;如何准确评估这些模型在不同输入模态下的性能成为了一个重要课题。本文提出了IsoBench&#xff0c;一个基准数据集&#xff0c;旨在通过提供多种同构&#xff08;isomorphic&#xff09;表示形式的问题&#xff0c;来测试和评估多模态…