前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >原子变量——原子操作

原子变量——原子操作

作者头像
程序员的园
发布2024-11-07 10:12:53
270
发布2024-11-07 10:12:53
举报
文章被收录于专栏:程序员的园——原创文章

原子变量一中做了原子变量的科普介绍,仅仅将普通变量升级为原子变量,便解决了多线程环境下的数据竞争问题。在应对如上的简单案例时,仅仅使用原子变量重载的操作++即可,为了应对更加复杂的使用场景,C++标准库提供了丰富的原子变量操作,使之无需加锁便可在多线程环境中操作共享数据。本文将对这些原子变量操作做更详细的说明。

在C++中,常用的原子变量操作包括:

  • store:存储/改写一个新值。
  • load:读取当前值。
  • exchange:交换当前值并返回旧值。
  • fetch_add、fetch_sub、fetch_and等:执行数学或逻辑操作并返回旧值。

虽然如上的每个操作均可以指定不同的内存序,如memory_order_relaxed(无序)、memory_order_acquire(获取)、memory_order_release(释放)等。但本文只聚焦所有的操作,内存序将在下一章节介绍。

让我们开始本文的原子变量操作之旅。

1. 存储操作

store操作将一个新值存储到原子变量中。

代码语言:javascript
复制
#include <iostream>
#include <atomic>
#include <thread>
std::atomic atomicInt{0};
void threadFunc() 
{
 atomicInt.store(10); // 设置新的值为10
}
int main() 
{
 std::thread t(threadFunc);
 t.join();
 std::cout << "Value after store: " << atomicInt.load() << std::endl;
 return 0;
}

2.加载操作

load操作从原子变量中读取当前值。

代码语言:javascript
复制
#include <iostream>
#include <atomic>
#include <thread>
std::atomic atomicInt{10};
void threadFunc() 
{
 int value = atomicInt.load(); // 读取值,确保同步性
 std::cout << "Loaded value: " << value << std::endl;
}
int main() 
{
 std::thread t(threadFunc);
 t.join();
 return 0;
}

3.交换操作

exchange操作用新值替换原子变量的当前值,并返回旧值。

代码语言:javascript
复制
#include <iostream>
#include <atomic>
#include <thread>
std::atomic atomicInt{ 10 };
void threadFunc() 
{
 int oldValue = atomicInt.exchange(20); // 将值替换为20
 std::cout << "Old value was: " << oldValue << std::endl;
}
int main() 
{
 std::thread t(threadFunc);
 t.join();
 std::cout << "Value after exchange: " << atomicInt.load() << std::endl;
 return 0;
}

4. 加法和减法操作

fetch_add和fetch_sub分别用于对原子变量执行加法和减法操作。它们返回操作之前的旧值。

代码语言:javascript
复制
#include <iostream>
#include <atomic>
#include <thread>
std::atomic atomicCounter{0};
void increment() 
{
 atomicCounter.fetch_add(1); // 增加1
}
void decrement() 
{
 atomicCounter.fetch_sub(1); // 减少1
}
int main() 
{
 std::thread t1(increment);
 std::thread t2(decrement);
 t1.join();
 t2.join();
 std::cout << "Counter after operations: " << atomicCounter.load() << std::endl;
 return 0;
}

5. 比较并交换

compare_exchange_weak和compare_exchange_strong用于比较并交换当前值。这些操作尝试将原子变量从给定的旧值更改为新值,并返回布尔值表示操作是否成功。

代码语言:javascript
复制
#include <iostream>
#include <atomic>
#include <thread>
std::atomic atomicInt{ 10 };
void tryExchange() 
{
 int expected = 8;
 bool success = atomicInt.compare_exchange_strong(expected, 20);
 if (success) {
 std::cout << "Exchange succeeded, new value: " << atomicInt.load() << std::endl;
 }
 else {
 std::cout << "Exchange failed, expected: " << expected << std::endl;
 }
}
int main() 
{
 std::thread t(tryExchange);
 t.join();
 return 0;
}
//返回值:失败,输入的预期值是8,但应该是10
//output:
//Exchange failed, expected: 10

compare_exchange_strong在原子变量当前值等于expected时,将其更新为新值20。若操作失败(即原子变量值不等于expected),则更新expected的值为当前的实际值。

6. 逻辑操作

对于位操作,fetch_and、fetch_or和fetch_xor允许对原子变量执行按位与、或和异或操作。

代码语言:javascript
复制
#include <iostream>
#include <atomic>
std::atomic flags{0b1010}; // 二进制1010
int main() 
{
 flags.fetch_or(0b0101); // 设置标志位
 std::cout << "Flags after OR: " << std::bitset<4>(flags.load()) << std::endl;
 flags.fetch_and(0b1110); // 清除标志位
 std::cout << "Flags after AND: " << std::bitset<4>(flags.load()) << std::endl;
 flags.fetch_xor(0b0011); // 反转标志位
 std::cout << "Flags after XOR: " << std::bitset<4>(flags.load()) << std::endl;
 return 0;
}

总结

本文介绍了C++中原子变量的各种操作,包括store、load、exchange、fetch_add、fetch_sub、compare_exchange和位操作。通过这些操作,可以在多线程环境中实现安全、无锁的数据操作。

本文的所示例代码均没有设置函数的最后一个参数——内存序,采用的是内存序的默认值——memory_order_seq_cst。内存序才是本系列专栏的最重要的知识点,只是为了循序渐见,方才有了上一篇和本篇文章。敬请期待下一篇文章。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-11-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员的园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档