首页 > 编程语言 >C++ 并发编程指南(11)原子操作

C++ 并发编程指南(11)原子操作

时间:2024-03-17 19:32:02浏览次数:28  
标签:11 std counter 编程 C++ 原子 操作 多线程

文章目录


前言

在C++多线程编程中,原子操作扮演着至关重要的角色。它们提供了一种在多线程环境中安全地访问和修改共享数据的方式,从而避免了数据竞争和不一致性的问题。本文将详细介绍C++中的原子操作,包括其定义、分类、使用方法以及在实际编程中的应用。

一、原子操作

1、基本概念

原子操作是指在多线程环境下,对数据的访问和修改是不可分割的,即在一个线程对数据进行操作的过程中,其他线程无法干预。这样可以确保数据的一致性和完整性。

原子操作可以确保数据的一致性和完整性,这一概念源自于数据库管理系统中的ACID属性,其中“A”代表原子性。原子性的核心在于确保事务(在数据库中)或操作序列(在多线程编程中)要么完全执行,要么完全不执行,不会出现只执行了部分的情况。

  • 确保数据一致性:原子操作通过保证一系列更改或者检查作为一个整体执行,来确保数据的一致性。这意味着在这个操作序列执行过程中,不受到其他线程的干扰,从而避免了数据处于不一致状态的可能性。
  • 确保数据完整性:原子操作防止了在执行过程中发生错误而导致的数据丢失或损坏。如果一个原子操作因为某种原因无法完成,那么它所做的所有更改都会被回滚,从而保证了数据的完整性。

总的来说,理解原子操作可以确保数据的一致性和完整性,关键在于认识到它们将一组操作封装为一个不可分割的单元,这个单元要么全部成功,要么在遇到错误时全部失败并恢复到操作前的状态,从而保护数据的正确性和可靠性。

2、C++中的原子类型

C++标准库提供了一组原子类型,如std::atomic<T>,其中T是任意基本数据类型,如int、float、double等。这些原子类型提供了一些成员函数,用于实现原子操作。以下是一些常用的原子操作成员函数:

  • load():读取原子变量的值,返回T类型的值。
  • store(T value):设置原子变量的值为value。
  • exchange(T value):设置原子变量的值为value,并返回之前的值。
  • compare_exchange_weak(T& expected, T desired):如果原子变量的值等于expected,则将其设置为desired,并返回true;否则返回false。
  • compare_exchange_strong(T& expected, T desired):与compare_exchange_weak类似,但在失败时会阻塞当前线程,直到成功为止。

3、示例

下面是一个简单的示例,展示了如何使用原子操作来实现一个计数器:

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

std::atomic<int> counter(0); // 定义一个原子整数变量

void increase_counter() {
    for (int i = 0; i < 1000; ++i) {
        counter.fetch_add(1, std::memory_order_relaxed); // 以宽松内存顺序增加计数器的值
    }
}

int main() {
    std::thread t1(increase_counter);
    std::thread t2(increase_counter);

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

    std::cout << "Counter: " << counter << std::endl; // 输出计数器的值

    return 0;
}

在这个示例中,我们定义了一个原子整数变量counter,并创建了两个线程t1t2,它们都调用increase_counter函数来增加计数器的值。由于我们使用了原子操作,所以即使在多线程环境下,计数器的值也能保持一致。

4、总结

C++中的原子操作提供了一种在多线程环境中安全地访问和修改共享数据的方式。通过使用std::atomic模板类和相关函数,我们可以实现各种基本和复合类型的原子操作。在实际编程中,原子操作被广泛应用于实现计数器、标志位、并发数据结构和算法等场景。通过合理地使用原子操作,我们可以有效地避免数据竞争和不一致性的问题,从而提高多线程程序的正确性和性能。

标签:11,std,counter,编程,C++,原子,操作,多线程
From: https://blog.csdn.net/cloud323/article/details/136787737

相关文章

  • C++算法学习心得八.动态规划算法(5)
    1.买卖股票的最佳时机(121题)题目描述:给定一个数组prices,它的第 i个元素 prices[i]表示一支给定股票第i天的价格。你只能选择某一天买入这只股票,并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取......
  • C++算法学习心得八.动态规划算法(4)
    1.零钱兑换(322题)题目描述:给定不同面额的硬币coins和一个总金额amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。你可以认为每种硬币的数量是无限的。示例 1:输入:coins=[1,2,5],amount=11输出:3解......
  • Python面向对象编程:合集篇(类、对象、封装、继承和多态)
    Python语言设计之初,就是为了面向对象。所以Python的面向对象更加易于理解。如果你以前学过Java、C++你大概就懂得什么是面向对象,但如果你是第一门编程语言就选择Python,那么也不要害怕。这篇文章,我们将会尽量详细的讲解,把Python面向对象编程的知识讲清楚。接下来我们先来简单的......
  • 通过Wine实现在mac和linux上实现masm编程
    原文链接:UsingMASMonMacorLinuxviaWine抄这个文档是因为它的确有用,mac下也能很好的学习windowsapi。而且我怕老外的文档无法访问。Wine是啥来百度百科一下:Wine(“WineIsNotanEmulator”的缩写)是一个能够在多种POSIX-compliant操作系统(诸如Linux,macOS及BSD......
  • Win11-鼠标右键菜单恢复为win10显示样式
    先看下win11默认的鼠标右键菜单显示情况看起来没有win10舒服解决方法:cmd命令行执行以下命令reg add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve 执行后重启Windows资源管理器 执行完以上操作后,效果如下......
  • C++STL第四篇(最简单的栈和队列)
    stack&queuestackstack是一种先进后出(FirstInLastOut,FILO)的数据结构,它只有一个出口,形式如图所示。stack容器允许新增元素,移除元素,取得栈顶元素,但是除了最顶端外,没有任何其他方法可以存取stack的其他元素。换言之,stack不允许有遍历行为。有元素推入栈的操作称为:push,将元......
  • qml使用c++的类
    QML使用C++的类qmlobjectdefine.h#ifndefQMLOBJECTDEFINE_H#defineQMLOBJECTDEFINE_H#include<qobjectdefs.h>#include<qqml.h>#defineQML_FUNCTIONQ_INVOKABLE#defineQML_MEMBER_NAME(NAME)......
  • C++20新特性-barrier
     以下内容由豆包大语言模型生成,内容仅供参考: C++20引入了一个新的标准库头文件 <barrier>,其中包含了对屏障(barrier)的支持。屏障是一种用于同步多个线程的同步原语,它允许线程在某个点上等待,直到所有线程都到达该点。C++20的 <barrier> 头文件提供了一个 std::barrier......
  • 【经验】关于c++11中string类型字符串和整形相互转化的用法
    https://blog.csdn.net/Elephant_King/article/details/129225134 c++11中为我们提供了许多非常方便的函数,可以帮助我们在整形与string类型字符串进行转换关于Dev-c++如何使用c++11,因为本人是mac系统,使用cLion,无法安装Dev,可以在网上搜其他教程实现整形转字符串(to_string())to_s......
  • 常见排序算法(C/C++)--- 动画演示
        本篇将介绍一些常见的排序算法,如插入排序:直接插入排序、希尔排序;选择排序:选择排序、堆排序;交换排序:快速排序、冒泡排序;以及最后的归并排序。    对于以上的排序算法,我们总结了每种排序算法的特性,接着对直接插入排序进行了优化;然后实现了归并排序和快速排......