C++ 并发与多线程:高级进阶

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

C++ 并发与多线程:高级进阶

\n\n

现代应用程序要求极致性能,而 C++ 中的多线程是实现这一目标的关键工具之一。然而,基本机制(如 std::thread、std::mutex)常常导致死锁、数据竞争和效率降低。本文将探讨 C++ 中并发编程的高级技术:从原子操作到无锁数据结构,再到异步任务。

\n\n

1. 原子操作与内存序

\n\n

经典的互斥锁是一种重量级机制。对于简单的计数器或标志,最好使用 std::atomic。它保证无锁的读/写原子性。然而,在高级层面,理解 内存序(C++ 内存模型,定义了线程间变更的可见性)至关重要。

\n\n

主要的内存序类型:

\n
    \n
  • memory_order_relaxed — 最小保证,仅保证原子性。
  • \n
  • memory_order_consume — 很少使用,依赖于数据。
  • \n
  • memory_order_acquire — 此操作之后的所有后续读/写不能被重排到此操作之前。
  • \n
  • memory_order_release — 此操作之前的所有写入在此操作之后对其他线程可见。
  • \n
  • memory_order_acq_rel — acquire 和 release 的组合。
  • \n
  • memory_order_seq_cst — 最严格,全局顺序一致性(默认)。
  • \n
\n\n

使用示例:

\n
#include <atomic>\n#include <thread>\n#include <cassert>\n\nstd::atomic<bool> ready{false};\nint data = 0;\n\nvoid producer() {\n    data = 42;                                   // 写入数据\n    ready.store(true, std::memory_order_release); // 发布标志\n}\n\nvoid consumer() {\n    while (!ready.load(std::memory_order_acquire)) // 等待标志\n        ;\n    assert(data == 42); // 保证看到 data == 42\n}\n\nint main() {\n    std::thread t1(producer);\n    std::thread t2(consumer);\n    t1.join();\n    t2.join();\n    return 0;\n}
\n\n

这里,release 和 acquire 保证 data 的写入发生在标志设置之前,而读取发生在标志设置之后。这比互斥锁更快。

\n\n

2. 无锁数据结构

\n\n

无锁算法通过使用原子操作和 CAS(比较并交换)来避免锁。经典示例是基于单链表的无锁栈。

\n\n

无锁栈的实现:

\n
#include <atomic>\n#include <memory>\n\ntemplate<typename T>\nclass LockFreeStack {\nprivate:\n    struct Node {\n        T data;\n        Node* next;\n        Node(const T& val) : data(val), next(nullptr) {}\n    };\n    std::atomic<Node*> head{nullptr};\n\npublic:\n    void push(const T& val) {\n        Node* new_node = new Node(val);\n        new_node->next = head.load(std::memory_order_relaxed);\n        while (!head.compare_exchange_weak(\n            new_node->next, new_node,\n            std::memory_order_release,\n            std::memory_order_relaxed)) {\n            // 循环直到 CAS 成功\n        }\n    }\n\n    bool pop(T& result) {\n        Node* old_head = head.load(std::memory_order_relaxed);\n        while (old_head != nullptr &&\n               !head.compare_exchange_weak(\n                   old_head, old_head->next,\n                   std::memory_order_acquire,\n                   std::memory_order_relaxed)) {\n            // 等待\n        }\n        if (old_head == nullptr) return false;\n        result = old_head->data;\n        // 注意:在实际代码中,需要垃圾回收或 hazard pointers\n        delete old_head;\n        return true;\n    }\n};
\n\n

重要说明:

\n
    \n

博客

书籍推荐