自学内容网 自学内容网

C++ 并发编程指南(11)原子操作 | 11.2、atomic_flag


前言

C++ atomic_flag是C++标准库中的一个原子标志类,用于实现线程间的同步和互斥。它是C++11引入的,提供了一种轻量级的原子操作方式,可以用于实现简单的互斥锁和条件变量等功能。

一、atomic_flag

std::atomic_flag 是 C++11 标准库中的一个类,它提供了一种简单的、无锁的、低开销的原子操作。std::atomic_flag 通常用于那些只需要两个状态的场景,例如作为一个标志或者是一个锁。它只能进行两种操作:设置(clear())和清除(test_and_set())。

1、特点

  • 简单性std::atomic_flag 提供了最基础的原子操作,没有提供复杂的比较和交换(compare-and-swap)或加载/存储操作。
  • 无锁:使用 std::atomic_flag 可以实现无锁编程,这通常意味着更高的性能,但也可能导致更复杂的代码。
  • 低开销:由于 std::atomic_flag 的操作非常简单,所以它的开销通常比其他更复杂的原子类型要小。

2、成员函数

  • clear():将标志设置为false
  • test_and_set():设置标志为true,并返回之前的值。
  • test_and_set_explicit():与test_and_set()类似,但可以指定一个内存顺序参数。
  • test_and_reset():设置标志为false,并返回之前的值。
  • test_and_reset_explicit():与test_and_reset()类似,但可以指定一个内存顺序参数。
  • wait():等待标志变为false
  • notify_one():唤醒等待该标志的一个线程。
  • notify_all():唤醒等待该标志的所有线程。

3、示例

下面是一个简单的示例,展示了如何使用 std::atomic_flag 来实现一个简单的自旋锁:

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

std::atomic_flag lock = ATOMIC_FLAG_INIT;

void critical_section() {
    while (lock.test_and_set()) {
        // 如果锁被其他线程持有,则忙等待(自旋)
    }
    // 临界区代码
    std::cout << "Thread " << std::this_thread::get_id() << " is in the critical section.\n";
    lock.clear(); // 释放锁
}

int main() {
    std::thread t1(critical_section);
    std::thread t2(critical_section);
    
    t1.join();
    t2.join();
    
    return 0;
}

在这个示例中,两个线程尝试进入临界区。由于使用了 std::atomic_flag 作为锁,所以只有一个线程能够同时进入临界区。当一个线程进入临界区后,它会设置 locktrue,然后执行临界区代码。当临界区代码执行完毕后,它会将 lock 清除为 false,允许其他线程进入临界区。

4、注意事项

  • std::atomic_flag 的初始值是不确定的,除非你使用 ATOMIC_FLAG_INIT 进行初始化。
  • 由于 std::atomic_flag 的功能非常简单,它可能不适合所有场景。对于更复杂的原子操作,你可能需要使用 std::atomic 模板类。
  • 在使用 std::atomic_flag 实现自旋锁时,需要注意忙等待(自旋)可能会导致 CPU 资源浪费。在需要等待较长时间的情况下,使用其他类型的锁(如互斥锁)可能更为合适。

原文地址:https://blog.csdn.net/cloud323/article/details/137855029

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!