当前位置: 首页 > wzjs >正文

网站建设地带最新发布的最新

网站建设地带,最新发布的最新,建设广告联盟网站,wordpress网站优化目录 1.引言 2.std::atomic 支持的复杂类型 3.std::atomic与无锁 4.如何使用 std::atomic 保护复杂类型 4.1.使用互斥锁(Mutex) 4.2.使用 std::atomic_flag 和自旋锁 4.3.原子共享指针(Atomic Shared Pointers) 4.4.使用高…

目录

1.引言

2.std::atomic 支持的复杂类型

3.std::atomic与无锁

4.如何使用 std::atomic 保护复杂类型

4.1.使用互斥锁(Mutex)

4.2.使用 std::atomic_flag 和自旋锁

4.3.原子共享指针(Atomic Shared Pointers)

4.4.使用高级同步机制

5.std::atomic 和 volatile 的区别

6.总结


1.引言

        std::atomic 是 C++11 标准库中的一个模板类,用于提供原子操作。原子操作是不可分割的操作,即在多线程环境下执行时,不会被线程调度机制打断。这保证了在多线程编程中,对共享数据的访问是安全的,避免了数据竞争和不一致性问题。

        std::atomic 可以用于基本数据类型,如整型(intlongbool 等)和指针类型。它提供了一套成员函数,用于执行原子读、写、交换、比较并交换等操作。如:

 

#include <iostream>
#include <atomic>
#include <thread>std::atomic<int> counter(0);void increment() {for (int i = 0; i < 1000; ++i) {++counter;}
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout << "Final counter value: " << counter << std::endl;return 0;
}

        std::atomic 还可以用于更复杂的类型,如自定义类和结构体,但使用复杂类型时有一些额外的限制和注意事项。

2.std::atomic 支持的复杂类型

C++11 标准引入了对复杂类型的原子支持,但需要满足以下条件:

必须是“平凡可复制”的类型

  • 只有**平凡可复制(Trivially Copyable)**的类型才能直接用于 std::atomic

  • 平凡可复制的含义:

    • 没有自定义的构造函数、析构函数、拷贝构造和拷贝赋值运算符。

    • 可以通过 memcpy 直接拷贝的类型。

C++之std::is_trivially_copyable(平凡可复制类型检测)_trivially copyable-CSDN博客

        示例如下:

#include <atomic>
#include <iostream>
#include <thread>struct Point {int x;int y;
};std::atomic<Point> point = Point{0, 0};void modify_point() {Point p = point.load();p.x += 1;p.y += 1;point.store(p);
}int main() {std::thread t1(modify_point);std::thread t2(modify_point);t1.join();t2.join();Point p = point.load();std::cout << "Point: (" << p.x << ", " << p.y << ")\n";return 0;
}

输出:

Point: (2, 2) 

解释: 

  • Point 是一个平凡可复制的类型,因此可以直接用 std::atomic<Point>

  • 由于原子性操作是对整个结构体进行的,但这里存在竞态条件,fetch_add 不适用于结构体。

不支持的类型示例(非平凡可复制):

#include <atomic>
#include <iostream>
#include <thread>struct Person {std::string name;int age;
};std::atomic<Person> person = Person{"Alice", 30}; // ❌ 编译错误int main() {return 0;
}

报错原因:

  • std::string 是一个复杂类型,包含动态内存分配,因此不是平凡可复制的类型。

3.std::atomic与无锁

   std::atomic<T>一定是无锁的吗?其实只要你花一点时间去翻一下cppreference.com就能得到答案:“不!”,因为std::atomic<T>提供了一个方法叫is_lock_free

        考虑以下几个结构体:

struct A { long x; };
struct B { long x; long y; };
struct C { char s[1024]; };

        A应当是无锁的,因为它显然等价于long。C应该不是无锁的,因为它实在是太大了,目前没有寄存器能存下它。至于B我们就很难直接推断出来了。

        对于x86架构的CPU,结构体B应当是无锁的,它刚刚好可以原子地使用MMX寄存器(64bit)处理。但如果它再大一点(比如塞一个int进去),它就不能无锁地处理了。

        原子操作究竟是否无锁与CPU的关系很大。如果CPU提供了丰富的用于无锁处理的指令与寄存器,则能够无锁执行的操作就会多一些,反之则少一些。除此之外,原子操作能否无锁地执行还与内存对齐有关。正因如此,is_lock_free()才会是一个运行时方法,而没有被标记为constexpr

4.如何使用 std::atomic 保护复杂类型

4.1.使用互斥锁(Mutex)

使用互斥锁(如 std::mutex)来保护对复杂类型数据的访问。这是最常见的方法,可以确保在任何时候只有一个线程可以访问数据。

#include <iostream>
#include <thread>
#include <mutex>struct ComplexType {int a;double b;std::string c;
};ComplexType data;
std::mutex dataMutex;void modifyData(int newA, double newB, const std::string& newC) {std::lock_guard<std::mutex> lock(dataMutex);data.a = newA;data.b = newB;data.c = newC;
}void printData() {std::lock_guard<std::mutex> lock(dataMutex);std::cout << "a: " << data.a << ", b: " << data.b << ", c: " << data.c << std::endl;
}int main() {std::thread t1(modifyData, 10, 20.5, "Hello");std::thread t2(printData);t1.join();t2.join();return 0;
}

4.2.使用 std::atomic_flag 和自旋锁

对于复杂类型,可以使用原子标志位实现自旋锁,保护整个临界区。

#include <atomic>
#include <iostream>
#include <thread>struct Person {std::string name;int age;
};Person person = {"Alice", 30};
std::atomic_flag lock_flag = ATOMIC_FLAG_INIT;void lock() {while (lock_flag.test_and_set(std::memory_order_acquire)) {} // 自旋等待
}void unlock() {lock_flag.clear(std::memory_order_release);
}void update_person() {lock();person.age += 1;std::cout << "Updated Age: " << person.age << "\n";unlock();
}int main() {std::thread t1(update_person);std::thread t2(update_person);t1.join();t2.join();std::cout << "Final Age: " << person.age << "\n";return 0;
}

解释:

  • 使用了 std::atomic_flag 实现了一个简单的自旋锁,保护了对 Person 结构体的访问。

  • 由于 std::string 是非平凡可复制类型,这里需要使用自旋锁来保护。

4.3.原子共享指针(Atomic Shared Pointers)

C++11 中,std::atomic 还支持 std::shared_ptr,用于管理对象的引用计数。这种技术特别适合实现并发的数据结构,避免对象的过早销毁或误用。

#include <atomic>
#include <memory>
#include <iostream>struct ComplexData {int value1;double value2;std::string value3;ComplexData(int v1, double v2, std::string v3): value1(v1), value2(v2), value3(v3) {}
};std::atomic<std::shared_ptr<ComplexData>> dataPtr;void updateData(int v1, double v2, const std::string& v3) {// 为新数据创建一个shared_ptrstd::shared_ptr<ComplexData> newData = std::make_shared<ComplexData>(v1, v2, v3);// 原子地替换旧数据std::atomic_store(&dataPtr, newData);
}void processData() {// 原子地读取共享指针std::shared_ptr<ComplexData> data = std::atomic_load(&dataPtr);if (data) {std::cout << "Current Data: " << data->value1 << ", " << data->value2 << ", " << data->value3 << std::endl;} else {std::cout << "Data pointer is null." << std::endl;}
}int main() {updateData(10, 20.5, "Test Data");processData();return 0;
}

在这个代码中:

  • ComplexData 结构体用于存储一个整数、一个双精度浮点数和一个字符串。
  • dataPtr 是一个原子性的 std::shared_ptr<ComplexData>,用于确保对复杂数据的线程安全访问。
  • updateData 函数创建一个新的 ComplexData 实例,并原子性地替换旧数据。
  • processData 函数原子性地读取数据并打印。

这样,即使在多线程环境中,对 dataPtr 的访问也是安全的,避免了数据竞争的问题。

4.4.使用高级同步机制

对于更复杂的同步需求,你可以考虑使用条件变量(std::condition_variable)、信号量(std::binary_semaphore,C++20 引入)等高级同步机制。

5.std::atomic 和 volatile 的区别

许多人常常混淆 std::atomic 和 volatile。二者在多线程中的作用非常不同:

  • volatile 只是告诉编译器不要对其进行优化,适用于处理与硬件相关的操作,无法保证线程安全。
  • std::atomic 是多线程同步原语,保证原子性和线程安全,适合多线程编程。
  • volatile int counter = 0;  // 不安全,不能用于多线程
    std::atomic<int> atomic_counter = 0;  // 线程安全

6.总结

        std::atomic 提供轻量、高效的原子操作,适用于不需要复杂锁机制的场景。同时需理解内存顺序对性能和正确性的影响。对于复杂的多操作组合,仍需谨慎处理竞态条件。不当使用 load 和 store 导致竞态条件、对内存顺序的误解、复合操作的不原子性。

参考:

https://en.cppreference.com/w/cpp/atomic/atomic

http://www.dtcms.com/wzjs/100231.html

相关文章:

  • 做网站服务器和域名店面怎么做位置定位
  • 建设通网站免费注册福州网站建设
  • 做食品的采购员常用网站最新疫情最新情况
  • 制作模板网站直通车推广技巧
  • 徐州html5响应式网站建设黑帽seo排名技术
  • 网上接单做效果图哪个网站好360网站推广费用
  • 贵州网站定制搜索引擎推广的方法有
  • 合肥市住房和城乡建设厅网站新闻热点事件2024最新
  • 十堰网站建设公司设计网页
  • wordpress文章图片显示大图seo页面链接优化
  • 关于建设工程资料的网站全网营销系统是干什么的
  • 用HTML和css做购物网站南宁网站推广大全
  • 橙子建站是真实的吗sku电商是什么意思
  • 青海省公路建设管理局官方网站网络培训心得体会
  • 做网站要实名吗百度推广获客
  • 电商设计师工作内容抖音seo系统
  • 一台云服务器可以做几个网站seo效果检测步骤
  • 长沙哪里做网站价格便宜站长之家的作用
  • 导购类网站模板软文营销文章300字
  • 做暖暖在线获取网站seo常用工具
  • 怎么做漫画网站市场营销策划方案3000字
  • 做宝玉石交易的网站有哪些做一个公司网页多少钱
  • 现在哪些网站自己做装修营销策划与运营方案
  • wordpress 插件制作seo价格查询公司
  • 济南营销网站建设公司如何进行搜索引擎优化?
  • 成都中小企业网站建设网站收录一般多久
  • 成都专业网站制作多少钱游戏推广员拉人技巧
  • 做任务游戏能赚钱的网站长安seo排名优化培训
  • 海尔集团的电子商务网站建设百度广告竞价
  • 旅游攻略那个网站做的好关键词权重