[modern c++] atomic

  • atomic库的底层也是有锁的,仅 std::atomic_flag 底层是不需要锁来辅助完成 atomic 操作,其他的类型包括 atomic<int> 、atomic<bool> 。。。 等在内部基本都是通过锁的机制来完成 atomic。不过具体情况要视编译器和操作系统而定,至少c++ 11标准中对于这块的要求是 expected ,而不是 required。
  • std::atomic_flag f=ATOMIC_FLAG_INIT; 是固定用法,即std::atomic_flag只能用ATOMIC_FLAG_INIT初始化,且默认状态是clear的。这是所有atomic类型中唯一有硬性要求的,同时flag也是唯一 100% lock-free的。
  •  所有的atomic 类型都是 no-copy(拷贝构造和拷贝赋值都被禁用) 和 no-move(移动构造和移动赋值都被禁用)的。但除了 flag 之外,其他都可以使用对应的 noatomic 类型值进行赋值。

  比如 atomic<bool> a_b = false;atomic<int> a_i = 10; 这些都是合法的 ;

  但是 atomic<bool> a_b1 = false;atomic<bool> a_b2 = a_b1 这个就是非法的;

  但是 atomic_flag a_f = true 就是非法的,atomic_flag 只能用 std::atomic_flag f=ATOMIC_FLAG_INIT ,可以武断的说它的赋值符号只能是这个值。

  • std::atomic_flag 的 test_and_set() 用来将 flag 设置为 true,同时通过返回值通知调用者之前的那个值是 false 还是 true,乍一看这个操作是不是应该就叫做 set 比较合适,但是细想确发现 test 确实是有作用的,因为std::atomic_flag 是保证 lock-free的,因此会执行的非常快,因为任何线程都不需要等待其他线程对于这个标志的操作。所以大家对于 std::atomic_flag 的操作都会被立刻响应,这恰恰造成一个问题,那就是调用者不知道是自己设置成的true?还是别人干的?所以这个函数通过返回值的方式告诉调用者,如果返回false,那么表示这次改变其实是由当前操作完成的,如果返回true,则说明这个标志在我们设置它之前就已经是true的了,其实我们没有做功。我们可以利用这个及时来实现一个自旋锁:

       

class spinlock_mutex
{
	std::atomic_flag flag;
public:
	spinlock_mutex():
	flag(ATOMIC_FLAG_INIT)
	{}
	void lock()
	{
        //如果test_and_set返回false,则说明是当前线程改变了标志位,那么相当于拿到锁了
        //因此跳出while循环,这也是自旋锁的语意 “ 反复忙等检查,直到条件满足 ”,atomic_flag
        //的 100% lock-free 特性正好满足 “忙等”
		while(flag.test_and_set(std::memory_order_acquire));
	}
	void unlock()
	{
		flag.clear(std::memory_order_release);
	}
};
  • std::atomic_flag在 c++ 20才引入 test() 函数,之前只有 构造、析构、clear、test_and_set。因此c++ 20之前我们没法在不修改flag的状态下查看当前的 flag值,所以除了自旋锁场景外,我们多会选择 atomic<bool> 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值