欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 时评 > 33、原子操作

33、原子操作

2025/6/8 14:13:07 来源:https://blog.csdn.net/m0_63008237/article/details/148482626  浏览:    关键词:33、原子操作

在 C++ 中,标准库提供了一些原子类型,主要用于多线程编程,以确保对变量的操作是原子的。以下是一些常见的原子类型:

  1. std::atomic<bool>
  2. std::atomic<char>
  3. std::atomic<signed char>
  4. std::atomic<unsigned char>
  5. std::atomic<short>
  6. std::atomic<unsigned short>
  7. std::atomic<int>
  8. std::atomic<unsigned int>
  9. std::atomic<long>
  10. std::atomic<unsigned long>
  11. std::atomic<long long>
  12. std::atomic<unsigned long long>
  13. std::atomic<wchar_t>
  14. std::atomic<char16_t>
  15. std::atomic<char32_t>
  16. std::atomic<std::intptr_t>
  17. std::atomic<std::uintptr_t>
  18. std::atomic<std::size_t>
  19. std::atomic<std::ptrdiff_t>
  20. std::atomic<void*>
  21. std::atomic<std::nullptr_t>

此外,std::atomic 还可以用于用户定义的类型,但这些类型必须是 trivially copyable 的。

例如:

#include <atomic>
#include <string>std::atomic<int> atomicInt{0};
std::atomic<bool> atomicBool{false};
std::atomic<std::string*> atomicStringPtr{nullptr};

这些类型可以确保在多线程环境中进行安全的读写操作。


std::atomic<void*> 代表的是指针类型吗

是的,std::atomic<void*> 代表的是一个原子指针类型。它可以用于存储和操作指针,并确保这些操作在多线程环境中是原子的。

例如:

#include <atomic>int main() {int a = 42;std::atomic<void*> atomicPtr{&a};// 读取指针值void* ptrValue = atomicPtr.load();// 修改指针值int b = 24;atomicPtr.store(&b);return 0;
}

在这个例子中,atomicPtr 是一个原子指针,可以安全地在多个线程之间共享和修改。


C++有那些相关的原子操作的api函数呢

在 C++ 中,标准库提供了一些与原子操作相关的 API 函数,这些函数主要在 <atomic> 头文件中定义。以下是一些常见的原子操作 API 函数:

  1. 加载和存储操作

    • load()
    • store()
  2. 交换操作

    • exchange()
  3. 比较并交换操作

    • compare_exchange_weak()
    • compare_exchange_strong()
  4. 算术操作

    • fetch_add()
    • fetch_sub()
    • fetch_and()
    • fetch_or()
    • fetch_xor()
  5. 内存顺序

    • memory_order_relaxed
    • memory_order_consume
    • memory_order_acquire
    • memory_order_release
    • memory_order_acq_rel
    • memory_order_seq_cst

以下是一些示例代码,展示了如何使用这些 API 函数:

#include <atomic>
#include <iostream>int main() {std::atomic<int> atomicInt{0};// 加载和存储操作atomicInt.store(10);int value = atomicInt.load();std::cout << "Value: " << value << std::endl;// 交换操作int oldValue = atomicInt.exchange(20);std::cout << "Old Value: " << oldValue << std::endl;std::cout << "New Value: " << atomicInt.load() << std::endl;// 比较并交换操作int expected = 20;bool exchanged = atomicInt.compare_exchange_strong(expected, 30);std::cout << "Exchanged: " << exchanged << std::endl;std::cout << "Current Value: " << atomicInt.load() << std::endl;// 算术操作atomicInt.fetch_add(5);std::cout << "After fetch_add: " << atomicInt.load() << std::endl;atomicInt.fetch_sub(3);std::cout << "After fetch_sub: " << atomicInt.load() << std::endl;return 0;
}

这些 API 函数可以确保在多线程环境中进行安全的原子操作。


compare_exchange_weak() 是 C++ 中的一个原子操作函数,用于在多线程环境中进行无锁编程。它尝试将原子对象的值与预期值进行比较,如果相等,则将其替换为新值。与 compare_exchange_strong() 不同,compare_exchange_weak() 可能会因为伪失败而返回 false,因此通常用于循环中。

以下是 compare_exchange_weak() 的用法示例:

#include <atomic>
#include <iostream>int main() {std::atomic<int> atomicInt{10};int expected = 10;int desired = 20;// compare_exchange_weak() 可能会伪失败,因此通常在循环中使用while (!atomicInt.compare_exchange_weak(expected, desired)) {// 如果失败,expected 会被更新为 atomicInt 的当前值std::cout << "Compare and exchange failed, expected: " << expected << std::endl;}std::cout << "Compare and exchange succeeded, new value: " << atomicInt.load() << std::endl;return 0;
}

在这个示例中,compare_exchange_weak() 尝试将 atomicInt 的值从 expected(10)更改为 desired(20)。如果 atomicInt 的当前值与 expected 相等,则更改成功并返回 true;否则,返回 false 并更新 expectedatomicInt 的当前值。由于 compare_exchange_weak() 可能会伪失败,因此通常在循环中使用它,直到操作成功为止。


什么是 “伪失败” ?

在 C++ 中,compare_exchange_weak()compare_exchange_strong() 都是用于原子比较并交换操作的函数。它们的主要区别在于 compare_exchange_weak() 可能会出现“伪失败”(spurious failure)。

伪失败(Spurious Failure)

伪失败是指在没有其他线程干扰的情况下,compare_exchange_weak() 也可能返回 false。这种情况通常是由于硬件实现的原因,特别是在某些架构上,弱的比较并交换操作可能会偶尔失败,即使预期值和当前值相等。

为什么使用 compare_exchange_weak()

尽管 compare_exchange_weak() 可能会出现伪失败,但它通常比 compare_exchange_strong() 更高效,因为它允许硬件使用更轻量级的指令。由于伪失败的可能性,compare_exchange_weak() 通常在循环中使用,以确保操作最终成功。

示例代码

以下是一个使用 compare_exchange_weak() 的示例,展示了如何处理伪失败:

#include <atomic>
#include <iostream>int main() {std::atomic<int> atomicInt{10};int expected = 10;int desired = 20;// compare_exchange_weak() 可能会伪失败,因此通常在循环中使用while (!atomicInt.compare_exchange_weak(expected, desired)) {// 如果失败,expected 会被更新为 atomicInt 的当前值std::cout << "Compare and exchange failed, expected: " << expected << std::endl;}std::cout << "Compare and exchange succeeded, new value: " << atomicInt.load() << std::endl;return 0;
}

在这个示例中,compare_exchange_weak() 尝试将 atomicInt 的值从 expected(10)更改为 desired(20)。如果 atomicInt 的当前值与 expected 相等,则更改成功并返回 true;否则,返回 false 并更新 expectedatomicInt 的当前值。由于 compare_exchange_weak() 可能会伪失败,因此通常在循环中使用它,直到操作成功为止。

实现无锁队列

实现无锁队列(Lock-Free Queue)是一项复杂的任务,通常需要使用高级的原子操作和内存序列。以下是一个简单的无锁队列实现示例,使用了 C++11 的原子操作。

无锁队列实现示例

#include <atomic>
#include <memory>
#include <iostream>template<typename T>
class LockFreeQueue {
private:struct Node {std::shared_ptr<T> data;std::atomic<Node*> next;Node(T value) : data(std::make_shared<T>(value)), next(nullptr) {}};std::atomic<Node*> head;std::atomic<Node*> tail;public:LockFreeQueue() {Node* dummy = new Node(T());head.store(dummy);tail.store(dummy);}~LockFreeQueue() {while (Node* old_head = head.load()) {head.store(old_head->next);delete old_head;}}void enqueue(T value) {Node* new_node = new Node(value);Node* old_tail = tail.load();while (true) {Node* next = old_tail->next.load();if (next == nullptr) {if (old_tail->next.compare_exchange_weak(next, new_node)) {tail.compare_exchange_weak(old_tail, new_node);return;}} else {tail.compare_exchange_weak(old_tail, next);}old_tail = tail.load();}}std::shared_ptr<T> dequeue() {Node* old_head = head.load();while (true) {Node* next = old_head->next.load();if (next == nullptr) {return std::shared_ptr<T>(); // Queue is empty}if (head.compare_exchange_weak(old_head, next)) {std::shared_ptr<T> result = next->data;delete old_head;return result;}old_head = head.load();}}
};int main() {LockFreeQueue<int> queue;queue.enqueue(1);queue.enqueue(2);queue.enqueue(3);std::shared_ptr<int> value;while ((value = queue.dequeue())) {std::cout << *value << std::endl;}return 0;
}

代码解释

  1. Node 结构体:每个节点包含一个数据指针和一个指向下一个节点的原子指针。
  2. 构造函数和析构函数:初始化队列时创建一个哑节点,并在析构时清理所有节点。
  3. enqueue 方法:将新节点添加到队列尾部。使用 compare_exchange_weak 确保操作是原子的。
  4. dequeue 方法:从队列头部移除节点。使用 compare_exchange_weak 确保操作是原子的。

这个实现是一个简单的无锁队列示例,适用于基本的多线程环境。对于更复杂的需求,可能需要更高级的无锁数据结构和算法。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词