美文网首页
原子性内存栅栏问题简述

原子性内存栅栏问题简述

作者: 码农苍耳 | 来源:发表于2018-03-29 01:55 被阅读168次

    内存栅栏(Memory fence),也称为内存屏障(Memory barrier),以前碰到这类概念都是基于锁的理解,比如dispatch_barrier。在看bmalloc的源代码时,发现其在使用原子性(atomic)的时候,出现了一种memory_order的概念,所以这里来简单看看原子性方面的问题。

    Atomic方法

    在iOS中,我们平时最常用的原子特性大部分来自于OSAtomic,可是当我打开这个文件的时候,却发现这些方法已经被弃用了。

    OSATOMIC_DEPRECATED_REPLACE_WITH(atomic_compare_exchange_strong)
    __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
    bool OSAtomicCompareAndSwap32( int32_t __oldValue, int32_t __newValue, volatile int32_t *__theValue );
    

    很好奇这个新的方法,它来自于C标注库stdatomic.h中,而这个头文件是C11才引入的,说明这是一个非常新的方法。而在C++11中,STL增强了C++的多线程编程能力,所以也是这个时候引入的std::atomic

    atomicvolidateatomic是真正的原子性,而volidate则仅标记对象为易变,提交给编译器优化使用的,并不能确保原子性。

    Memory Order

    typedef enum memory_order {
      memory_order_relaxed = __ATOMIC_RELAXED,
      memory_order_consume = __ATOMIC_CONSUME,
      memory_order_acquire = __ATOMIC_ACQUIRE,
      memory_order_release = __ATOMIC_RELEASE,
      memory_order_acq_rel = __ATOMIC_ACQ_REL,
      memory_order_seq_cst = __ATOMIC_SEQ_CST
    } memory_order;
    

    关于memory_order这个概念,非常的令人困惑。其关键就是atomic能够保证单个的操作的原子性,但不能保证两个原子操作之间的顺序,这涉及到CPU对缓存刷新时进行的顺序重排。这里看两个简单的例子就可以理解了:

    fence1.png fence2.png

    和我们平时的理解完全不一样,内存的修改顺序和实际的顺序居然可能不一致,这就是为什么会引入memory_order这个概念了。

    Spin lock

    最后再来看看SpinLock的实现,所有SpinLock都是基于原子操作进行的,目前我碰到的大致分为两种:

    1. 比较无赖,强制for循环等待
    2. 比较友善,在超过一定循环次数,会放弃当前时间片

    伪代码:

    atomic flag
    while flag:
        loop_count++
        if loop_count > MAX_LOOP_COUNT:
            yield  // iOS中可以是thread_swtich
    

    所以当某些调度算法,即使是在优先级高的线程中yield放弃时间片,依然不能分配给优先级低的线程,就会导致优先级反转而死锁。

    参考

    A Tutorial Introduction to the ARM and POWER Relaxed Memory Models

    相关文章

      网友评论

          本文标题:原子性内存栅栏问题简述

          本文链接:https://www.haomeiwen.com/subject/buppcftx.html