首页 > 其他分享 >std::atomic 使用

std::atomic 使用

时间:2024-03-25 17:49:09浏览次数:27  
标签:std noexcept 使用 atomic memory include order

std::atomic(原子变量)

参考文章包括:

C++原子变量atomic详解 - 知乎 (zhihu.com)

C++ 中的原子变量(std::atomic)使用指南_std::atomic-CSDN博客

cplusplus.com/reference/atomic/atomic/


原子变量是C++ 11中用于多线程编程的便捷工具(同步机制)之一.其提供了一种线程安全的方式来访问和修改共享数据(原子操作),从而无需显式的调用互斥锁,避免了竞态条件(race condition)和死锁(deadlock)等问题.

std::atomic 支持各种数据类型,如整数,布尔值,指针等,通过std::atomic<T>定义:

std::atomic<int> atomicInt(0);
std::atomic<bool> atomicBool(false);
std::atomic<double> *atomicString = new std::atomic<double>(3.1415);
is_lock_free函数:
bool is_lock_free() const volatile noexcept;
bool is_lock_free() const noexcept;

返回当前atomic对象是否支持无锁操作,是则返回true,反之返回false;

#include <iostream>
#include <atomic>

int main(int argc,char**argv)
{
    std::atomic<int> x(10);
    std::cout << std::boolalpha
                << "std::atomic<int> is_lock_free ?\n"
                << x.is_lock_free()
                << std::endl;

    return 0;
}

输出:

std::atomic<int> is_lock_free ?
true
load函数:
T load(memory_order sync = memory_order_seq_cst) const volatile noexcept;
T load(memory_order sync = memory_order_seq_cst) const noexcept;
operator T() const noexcept;

用于获取原子变量的当前值.

load函数的参数memory_order表示内存序,也就是对原子变量的读操作要遵循哪种内存模型。C++中定义了多种内存序,包括:

  • memory_order_relaxed:最轻量级的内存序,不提供任何同步机制。
  • memory_order_acquire:在本线程中,所有后面的读写操作必须在这个操作之后执行。
  • memory_order_release:在本线程中,该操作之前的所有读写操作必须在这个操作之前执行。
  • memory_order_seq_cst:最严格的内存序,保证所有线程看到的读写操作的顺序都是一致的。

使用load函数时,如果不指定memory_order,则默认为memory_order_seq_cst。

load函数的返回值类型为T,即原子变量的类型。在使用load函数时需要指定类型参数T。如果使用第二种形式的load函数,则无需指定类型参数T,程序会自动根据上下文推断出类型。

store函数:
void store(T desired, std::memory_order order = std::memory_order_seq_cst) volatile noexcept;
void store(T desired, std::memory_order order = std::memory_order_seq_cst) noexcept;

用于将给定的值存储到该原子变量中(desired 为要存储的值)

#include <iostream>
#include <atomic>

int main(int argc,char**argv)
{
    std::atomic<int> x(10);
    std::cout << x.load(std::memory_order_relaxed) 
        		<< std::endl;
	x.store(22,std::memory_order_relaxed);
    std::cout << x.load(std::memory_order_relaxed) 
        		<< std::endl;

    return 0;
}

输出:

10
22
exchange函数:
template< class T >
T exchange( volatile std::atomic<T>* obj, T desired );

访问和修改包含的值.

obj指向需要替换值的atomic对象,desired为期望被替换成的值,若替换成功,返回原来被替换的值.

此函数整体为原子操作,直到返回值的那一刻,都不受其他线程影响.

#include <iostream>       // std::cout
#include <atomic>         // std::atomic
#include <thread>         // std::thread
#include <vector>         // std::vector

std::atomic<bool> ready (false);
std::atomic<bool> winner (false);

void count1m (int id) {
  while (!ready) {}                  // wait for the ready signal
  for (int i=0; i<1000000; ++i) {}   // go!, count to 1 million
  if (!winner.exchange(true)) { std::cout << "thread #" << id << " won!\n"; }
};

int main ()
{
  std::vector<std::thread> threads;
  std::cout << "spawning 10 threads that count to 1 million...\n";
  for (int i=1; i<=10; ++i) threads.push_back(std::thread(count1m,i));
  ready = true;
  for (auto& th : threads) th.join();

  return 0;
}

输出:

spawning 10 threads that count to 1 million...
thread #4 won!
compare_exchange_strong / compare_exchange_weak函数:
bool compare_exchange_strong(T& expected, T desired, memory_order success = memory_order_seq_cst, memory_order failure = memory_order_seq_cst) noexcept;

bool compare_exchange_weak (T& expected, T val,memory_order sync = memory_order_seq_cst) volatile noexcept;
bool compare_exchange_weak (T& expected, T val,memory_order sync = memory_order_seq_cst) noexcept;
bool compare_exchange_weak (T& expected, T val,memory_order success, memory_order failure) volatile noexcept;
bool compare_exchange_weak (T& expected, T val,memory_order success, memory_order failure) noexcept;

两者的作用都是比较一个值与期望值是否相等,相等时替换为新值,strong会保证操作的原子性(expected:期望值,desired:新值,success:执行成功时执行的内存序列的类型,同failure).weak版本可能会在某些平台上出现失败并重试.

#include <iostream>       // std::cout
#include <atomic>         // std::atomic
#include <thread>         // std::thread
#include <vector>         // std::vector

// a simple global linked list:
struct Node { int value; Node* next; };
std::atomic<Node*> list_head (nullptr);

void append (int val) {     // append an element to the list
  Node* oldHead = list_head;
  Node* newNode = new Node {val,oldHead};

  // what follows is equivalent to: list_head = newNode, but in a thread-safe way:
  while (!list_head.compare_exchange_weak(oldHead,newNode))
    newNode->next = oldHead;
}

int main ()
{
  // spawn 10 threads to fill the linked list:
  std::vector<std::thread> threads;
  for (int i=0; i<10; ++i) threads.push_back(std::thread(append,i));
  for (auto& th : threads) th.join();

  // print contents:
  for (Node* it = list_head; it!=nullptr; it=it->next)
    std::cout << ' ' << it->value;
  std::cout << '\n';

  // cleanup:
  Node* it; while (it=list_head) {list_head=it->next; delete it;}

  return 0;
}

输出:

4 0 5 2 3 8 9 7 6 1
fetch系列专业化支持:
fetch_add 添加到包含的值并返回它在操作之前具有的值
fetch_sub 从包含的值中减去,并返回它在操作之前的值。
fetch_and 读取包含的值,并将其替换为在读取值和 之间执行按位 AND 运算的结果。
fetch_or 读取包含的值,并将其替换为在读取值和 之间执行按位 OR 运算的结果。
fetch_xor 读取包含的值,并将其替换为在读取值和 之间执行按位 XOR 运算的结果。

标签:std,noexcept,使用,atomic,memory,include,order
From: https://www.cnblogs.com/NekoBlog/p/18094917

相关文章

  • JAVA 使用POI实现单元格行合并
    POI实现单元格行合并实现效果引入jar代码实现controller层Service层ServiceImpl层实现类实现效果如果最后面的三行数据大于1时那么前面十二行就需要行合并引入jar<dependency><groupId>org.apache.poi</groupId><artifactId......
  • Vs Code中运行vue命令显示"系统禁止运行脚本"无法在终端使用
    右键点击vscode中的属性,在上面找到兼容性一栏,勾选里面以管理员身份运行在当前电脑中搜索WindowsPowerShell以管理员的身份运行 在里面输入 set-ExecutionPolicyRemoteSigned选择权限A ......
  • python中的unittest使用介绍
    unittest 是Python标准库中的一个模块,用于编写和运行单元测试。它提供了一个框架,让开发者可以轻松地编写测试用例、组织测试套件以及执行测试。下面是一个简单的示例,演示如何使用 unittest 模块:importunittestdefadd(a,b):returna+bclassTestAddFunction(un......
  • react 中echarts-for-react使用resize解决图表自适应问题
     importReact,{PureComponent}from"react";importReactEchartsfrom'echarts-for-react';import{useEventListener}from'ahooks';useEventListener('resize',()=>{ref?.current?.getEch......
  • 突破距离限制 远程级联测径仪 让您使用更安心!
    关键词:在线测径仪,测径仪,远程级联在现代工业领域,测量的准确性和高效性至关重要。在线测径仪不仅具备了这两项特质,更能进行远程级联,能更快速的为您解决软件系统在使用中遇到的问题。在线测径仪能做到以下几点精准测量,毫厘不差:先进的测量技术确保了直径测量的高精度,让您......
  • doctest使用方法
    doctest 是Python标准库中的一个模块,用于测试模块中的文档字符串中的示例代码。它可以确保文档字符串中的示例代码与实际代码行为一致,并且可以作为文档的一部分保持更新。以下是一个简单的示例,演示如何使用 doctest 模块:defadd(a,b):"""返回两个数字的和。......
  • 怎么批量删除docker没有使用的镜像 清理磁盘空间
    要批量删除没有使用的Docker镜像并清理磁盘空间,您可以按照以下步骤执行操作:1.查看当前使用的Docker镜像列表,可以使用以下命令:dockerimages2.确认需要删除的镜像是没有被使用的。如果您确定要删除某个镜像,请记录镜像的REPOSITORY和TAG。3.执行以下命令来删除指定镜......
  • std::async
    C++11提供了异步接口std::async,通过这个异步接口可以很方便的获取线程函数的执行结果。std::async会自动创建一个线程去调用线程函数,它返回一个std::future,这个future中存储了线程函数返回的结果,当我们需要线程函数的结果时,直接从future中获取,非常方便。但是我想说的是,其实std::as......
  • 使用dpkg在ubuntu上安装软件包遇到依赖包的问题
    问题在ubuntu上使用apt-get安装软件包,系统会自动安装依赖的软件包,但是使用dpkg在ubuntu上安装软件包时不会,有时会遇到下面的错误:pengdl@pengdl-HP:~/Soft$sudodpkg-ivirtualbox-7.0_7.0.14-161095~Ubuntu~focal_amd64.deb[sudo]passwordforpengdl:Selectingpreviously......
  • PT工具使用介绍
    PT工具的使用目录PT工具的使用pt-online-schema-change在线添加字段在线添加索引在线修改表字段pt-archiver数据清理数据归档参数说明:pt-archiverBug不会迁移max(id)那条数据的解决方法:删除老数据(单独的删数据操作不用指定字符集)复制数据到其他mysql实例,且不删除source的数据(......