首页 > 其他分享 >atomic原子,自旋锁与atomic_flag

atomic原子,自旋锁与atomic_flag

时间:2024-10-05 11:22:00浏览次数:7  
标签:std 自旋 flag atomic memory order 内存

1)原子类型
原子操作默认采用的是memory_order_seq_cst内存顺序

原子类型可以是无锁的,也可以有锁
(c++17)通过静态函数std::atomic::is_always_lock_free 判断
(c++11)通过成员函数 is_lock_free()判断

2)有锁or无锁

性能:无锁操作通常比有锁操作更快,因为它们不需要操作系统级别的同步机制。无锁操作可以直接利用硬件的原子指令,这通常比软件锁更高效。

3)自旋锁与atomic_flag
atomic_flag一般初始化为std::atomic_flag ready_flag = ATOMIC_FLAG_INIT(初始值为false)
此时,atomic_flag已被设置过(clear/初始化都算),调用test_and_set, atomic_flag置为true,返回false;
此后再调用test_and_set,都会返回true

std::atomic_flag 是一个非常轻量级的原子类型,适用于需要高效同步的场景。它通常用于实现自旋锁、一次性初始化和忙等待等同步机制。
虽然它的功能相对简单,但在多线程编程中非常有用,尤其是在对性能要求较高的应用中

自旋锁(Spin Locks):
自旋锁是一种简单的锁机制,当一个线程尝试获取已经被占用的锁时,它不会立即进入睡眠状态,而是不断循环检查锁的状态,直到锁可用为止。
自旋锁适用于锁的竞争不激烈且持有时间很短的场景,因为长时间的自旋会浪费 CPU 资源。
自旋锁是一种在多线程环境下保护共享资源的同步机制。它的基本思想是,当一个线程尝试获取锁时,
如果锁已经被其他线程持有,那么该线程就会不断地循环检查锁的状态,直到成功获取到锁为止。

std::atomic_flag的test_and_set成员函数是一个原子操作,他会先检查std::atomic_flag当前的状态是否被设置过,

1 如果没被设置过(比如初始状态或者清除后),将std::atomic_flag当前的状态设置为true,并返回false。
2 如果被设置过则直接返回ture。

4) 自旋锁的逻辑
第一次lock之后,atomic_flag被改变,其他lock调用被阻塞
unlock之后,atomic_flag状态被重置,其他lock调用继续运行

自旋锁设置时使用memory_order_acquire内存次序,在清除时使用了memory_order_release内存次序。

实现:```

class SpinLock {
public:
void lock() {
//1 处
while (flag.test_and_set(std::memory_order_acquire)); // 自旋等待,直到成功获取到锁
}

void unlock() {
    //2 处
    flag.clear(std::memory_order_release); // 释放锁
}

private:
std::atomic_flag flag = ATOMIC_FLAG_INIT;
};



调用:类似一个普通锁

void TestSpinLock() {
SpinLock spinlock;
std::thread t1(&spinlock {
spinlock.lock();
for (int i = 0; i < 3; i++) {
std::cout << "*";
}
std::cout << std::endl;
spinlock.unlock();
});

std::thread t2([&spinlock]() {
    spinlock.lock();
    for (int i = 0; i < 3; i++) {
        std::cout << "?";
    }
    std::cout << std::endl;
    spinlock.unlock();
    });


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

}




5)内存顺序

内存顺序概述
在多线程编程中,内存顺序(memory order)决定了原子操作的内存可见性和顺序。不同的内存顺序标记会影响编译器和处理器对内存访问的优化,从而影响程序的行为。C++ 提供了以下几种内存顺序标记:

std::memory_order_relaxed:最弱的内存顺序,仅保证当前操作的原子性,不提供任何额外的内存顺序保证。

std::memory_order_seq_cst:最强的内存顺序,确保所有线程看到的操作顺序是一致的,提供全局的顺序一致性。


std::memory_order_acquire:确保当前原子操作之前的所有读取操作在当前操作之后对其他线程可见。
std::memory_order_release:确保当前原子操作之前的所有写入操作在当前操作之后对其他线程可见。
std::memory_order_acq_rel:结合了 acquire 和 release 的效果,既确保当前操作之前的读取操作对其他线程可见,也确保当前操作之后的写入操作对其他线程可见。
使用:
对原子变量的 load 可以使用 memory_order_acquire 内存顺序. 这称为 acquire 操作.
对原子变量的 store 可以使用 memory_order_release 内存顺序. 这称为 release 操作.
read-modify-write 操作即读 (load) 又写 (store), 它可以使用 memory_order_acquire, memory_order_release 和 memory_order_acq_rel:

std::memory_order_consume:确保后续对依赖于当前原子操作结果的变量的读取是有序的。
使用:
多用于指针类型的原子
6)内存模型

happens-before
如果操作 a “happens-before” 操作 b, 则操作 a 的结果对于操作 b 可见
happens-before 的关系可以建立在用一个线程的两个操作之间, 也可以建立在不同的线程的两个操作之间。

标签:std,自旋,flag,atomic,memory,order,内存
From: https://www.cnblogs.com/light-LifeClub/p/18442762

相关文章

  • CAS原子类:AtomicLongArray源码解析
    AtomicLongArray内部维护了一个int类型的数组,需要先复习下数组对象的在内存中的结构,这对接下来对数组类型原子类的理解至关重要。一、数组对象的内存结构我们运行以下代码并将数组对象的内存结构通过JOL工具打印出来,关于这部分知识,参考之前的文章:深入理解Java对象结构publiccl......
  • 余大嘴立新flag 鸿蒙智行五年内成为中国高端车市场第一
    华为常务董事、终端BG董事长、智能汽车解决方案BU董事长余承东和马东今日开启一场直播活动,介绍了鸿蒙智行旗下问界M9、享界S9、智界R7等产品情况。当被问及鸿蒙智行五年内的目标是什么?余承东表示,至少五年内能够成为中国市场高端车第一,包括三十万以上、四十万以上、五十万......
  • disp_buffer_flags 枚举定义了一系列用于描述 framebuffer(帧缓冲区)特性的标志位
    disp_buffer_flags 枚举定义了一系列用于描述framebuffer(帧缓冲区)特性的标志位。这些标志位主要用于指示framebuffer的内容是如何组织的,特别是当涉及到立体视觉(3D显示)时。这些标志允许系统或应用程序知道如何正确地处理和显示framebuffer中的数据。下面是对每个标志位的具......
  • 事务 Atomicity Consistency Isolation Durability
    事务分类:原子性(Atomicity),一致性(Consistency),隔离性(Isolation),持久性(Durability)。原子性:(Atomicity)被执行的事务要么全部成功,要么全部失败,不能只单独执行一个。例如:有两个用户A和B,A原本有1000元,B原本有500元,A向B转账200元,将执行A变成800元和B变成700元,或者A不变并且B也不变,这两......
  • go flag的常用设置
    packagemainimport("bytes""encoding/json""flag""fmt""io/ioutil""net/http""os")varZabbixTarget,ZabbixMessage,ZabbixType,PrometheusAlertUrlstringvarhelp......
  • Flags
    Flags是位字段的序列,当其中任何一个位不为零且广播可连接时广播包中应包含flags.否则,flags可以被忽略。flags只能包含在广播包中,扫描响应包中不能包含flags。flags的作用是在广播包中加入如下标志:有限可发现模式;一般可发现模式;不支持BR/EDR;设备同时支持LE和BR/EDR;(控......
  • 自旋锁(Spinlock)和互斥锁(Mutex)的区别
    自旋锁(Spinlock)和互斥锁(Mutex)的区别自旋锁(Spinlock)和互斥锁(Mutex)都是用于多线程或多进程环境中同步共享资源的机制,但它们的工作方式和使用场景存在显著的不同。1.自旋锁(Spinlock)原理:当一个线程试图获取自旋锁时,如果锁已经被其他线程占有,它会一直循环检查(自旋)锁的状态,直到锁......
  • RickdiculouslyEasy靶场(9个flag)
    flag11.nmap扫描所有端口nmap172.16.1.7-p1-65535nmap-A-v-T417-p1-655352.13337端口存在一个flagFLAG:{TheyFoundMyBackDoorMorty}-10Pointsflag21.21端口对应的ftp服务可能存在匿名访问的问题,并且在该目录下面存在一个flag2.访问靶机上面的ftp服务,获......
  • AtomicStampedReference
    概述An{@codeAtomicStampedReference}maintainsanobjectreferencealongwithaninteger"stamp",thatcanbeupdatedatomically.包含一个对象引用+一个int的戳(Stamp),能被原子更新;Implementationnote:Thisimplementationmaintainsstampedref......
  • 获取rem像素转换比例 flag为true返回数字
    //获取rem像素转换比例flag为true返回数字exportfunctiongetRem(px,flag){px=(px||0)+''if(!(px.indexOf('%')!==-1||px.indexOf('rem')!==-1)){px=(Number(px)/40)+'rem'}if(flag){returnN......