C++ 并发专题 - 原子等待(atomic wait)

一:概述

        原子等待是 C++20 引入的一个特性,主要用于多线程编程中。它允许线程高效地等待某个原子变量的值变化,而不是使用忙等待(busy waiting),这样可以减少 CPU 资源的浪费,提高程序的性能。

        原子等待的引入主要是为了提高性能和资源利用率,尤其是在以下场景中:

  1. 减少上下文切换:传统的等待机制(如互斥锁、条件变量)常常涉及线程的阻塞与唤醒,这会导致上下文切换的开销。原子等待则允许线程在等待时进入休眠状态,避免了这些开销。

  2. 提高效率:在多线程环境中,频繁的状态变化可能会导致大量的线程等待和唤醒,使用原子等待可以更高效地管理这些状态变化,降低 CPU 的负担。

  3. 简化实现:原子等待提供了一种简单的机制,使得开发者可以更方便地实现高效的无锁数据结构和算法。

  4. 适用于高竞争场景:在高竞争的场景中,传统的锁机制可能会导致严重的性能下降,而原子等待能够减少锁竞争带来的问题。

二:多线程编程中还有哪些等待机制:

        在多线程编程中,除了原子等待之外,还有几种常见的等待机制,每种机制都有其特定的使用场景和优缺点:

1. 忙等待(Busy Waiting)

  • 描述:线程循环检查某个条件是否满足,一直占用 CPU。

  • 优点:实现简单,延迟较低。

  • 缺点:浪费 CPU 资源,导致性能下降,尤其在高负载时。

2. 互斥锁(Mutex)

  • 描述:使用互斥锁控制对共享资源的访问,线程在获取不到锁时会阻塞。

  • 优点:适用于复杂的临界区,能有效防止数据竞争。

  • 缺点:锁的开销较大,可能导致死锁、优先级反转等问题。

3. 条件变量(Condition Variable)

  • 描述:与互斥锁配合使用,线程可以在条件变量上等待,当条件满足时被通知。

  • 优点:避免了忙等待,可以在条件满足时高效唤醒线程。

  • 缺点:相对复杂,需要正确管理互斥锁和条件变量。

4. 信号量(Semaphore)

  • 描述:允许多个线程访问共享资源的计数器。线程在访问资源时可以增加或减少信号量。

  • 优点:可以控制同时访问共享资源的线程数量。

  • 缺点:实现复杂,容易导致资源竞争和死锁。

三:原子等待的例子:

#include <iostream>
#include <atomic>
#include <thread>
#include <chrono>

std::atomic<int> atomicValue(0);

void waitingThread() {
    std::cout << "线程正在等待原子变量的值改变...\n";
    int expected = 0;
    std::atomic_wait(&atomicValue, expected);
    std::cout << "线程恢复执行!原子变量的值变为: " << atomicValue.load() << "\n";
}

void notifyingThread() {
    std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟工作
    atomicValue.store(1);
    std::atomic_notify_one(&atomicValue);
    std::cout << "已通知等待的线程。\n";
}

int main() {
    std::thread t1(waitingThread);
    std::thread t2(notifyingThread);

    t1.join();
    t2.join();

    return 0;
}
#include <atomic>
#include <iostream>
#include <thread>

std::atomic<bool> atomicBool{};

void doTheWork(){
    std::cout << "Processing shared data." << '\n';
}

void waitingForWork(){
    std::cout << "Worker: Waiting for work." << '\n';
    atomicBool.wait(false);
    doTheWork();
    std::cout << "Work done." << '\n';
}

void setDataReady(){
    atomicBool.store(true);
    std::cout << "Sender: Data is ready."  << '\n';
    atomicBool.notify_one();
}

int main(){

    std::cout << '\n';

    std::thread t1(waitingForWork);
    std::thread t2(setDataReady);

    t1.join();
    t2.join();

    std::cout << '\n';
  
}

猜你喜欢

转载自blog.csdn.net/zg260/article/details/143440857