内联汇编相关

CAS与内存屏障: 内联汇编的实际应用场景_(S2实现CAS)

2018-07-16  本文已影响14人  Quasars

c++的CAS与内存屏障: 从c/c++的内联汇编说起(S3)

现在讨论下内联汇编与CAS

lock-free是什么?(理论)

是无阻塞编程的一种范式,允许一部分线程饥饿,但保证整个进程总能在有限时钟周期内结束.与此相对应的,还有wait-free,obstruction-free.

范式 含义
wait-free 每个线程总能在有限时钟周期内完成.
lock-free 整个进程能在有限时钟周期内完成,允许部分线程饥饿.
obstruction-free 在隔离的状态下,每个线程能在有限时钟周期内完成.

现在再看看lock-free与传统阻塞型编程范式的区别

范式 含义 同步原语
lock-free 整个进程能在有限时钟周期内完成,允许部分线程饥饿. 范式可以提供整个进程不会出现死锁、活锁和优先级翻转的保证. compare_and_swap, fetch_and_add等
阻塞型编程 临界区内1个线程持有互斥量,其他线程被阻塞;若持有锁的线程死亡,其他线程会出现死锁;若多个线程之间同步条件设计不合理,可能出现活锁;当优先级较低的线程持有资源还能造成优先级翻转. mutex,semaphore(互斥量,信号量)

经常在一些地方可以看到这样的论述,无锁编程可以避免多余的上下文切换.这个说法其实比较笼统,这里有2个问题:上下文切换指什么? 为什么无锁编程可以避免多余上下文切换?

下面看一下传统阻塞型同步.


lock-free的aba问题(理论)

实践部分

  1. lock-free同步原语的实现
- 同步原语的实现
- 与内存模型的关系
  1. 利用同步原语可以做什么?
- 实现阻塞型编程的互斥量和自旋锁(参见`nginx`)
- 实现lock-free数据结构

lock-free同步原语的实现

 - `sete dst`:若标记位ZF为1,则设置dst为1
 - `lock`:多处理器SMP时,锁定总线. `lock + 指令`可以保证后面`指令`执行期间其他CPU无法访问内存,当指令执行结束后放开锁定从而保证指令涉及的内存操作的原子性. 另外容易看出,由于cas只涉及1个指令,在单处理机体系中cas操作显然是原子的.

 - 破坏寄存器列表中的`cc`和`memory`, `cc`指标记位寄存器失效;`memory`则指所有内存都可能被改变,换言之,这将无效化cpu`L1-L3缓存`,下一条指令的访存操作将直接从内存取数据. 另外提一下,`memory`放置于破坏寄存器列表中并且前面几个域都为空经常作为内存屏障使用.

 - `原子性`的讨论: 软件的原子性实际上依赖于硬件提供的原子性.
 问:`x++`是否是原子的?不是,是3个指令,`取x,x+1,存入x`。
 >在单处理器上,如果执行x++时,禁止多线程调度,就可以实现原子。因为单处理的多线程并发是伪并发。在多处理器上,需要借助cpu提供的Lock功能。锁总线。读取内存值,修改,写回内存三步期间禁止别的CPU访问总线。同时我估计使用Lock指令锁总线的时候,OS也不会把当前线程调度走了。要是调走了,那就麻烦了。
compare_and_swap
8 #if (NGX_SMP)
9 #define NGX_SMP_LOCK  "lock;"
10 #else
11 #define NGX_SMP_LOCK
12 #endif
....
....
....
37 static ngx_inline ngx_atomic_uint_t
38 ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
39     ngx_atomic_uint_t set)
40 {   
41     u_char  res;
42     
43     __asm__ volatile (
44
45          NGX_SMP_LOCK
46     "    cmpxchgl  %3, %1;   "
47     "    sete      %0;       "
48     
49     : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory");
50     
51     return res;
52 }
fetch_and_add
 96  * gcc 2.7 does not support "+r", so we have to use the fixed
 97  * %eax ("=a" and "a") and this adds two superfluous instructions in the end
 98  * of code, something like this: "mov %eax, %edx / mov %edx, %eax".
 99  */
100
101 static ngx_inline ngx_atomic_int_t
102 ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add)
103 {
104     ngx_atomic_uint_t  old;
105
106     __asm__ volatile (
107
108          NGX_SMP_LOCK
109     "    xaddl  %2, %1;   "
110
111     : "=a" (old) : "m" (*value), "a" (add) : "cc", "memory");
112
113     return old;
114 }

无需再解释。

同步原语的原子性与其跟内存模型的关系(简要)

to be continued.

利用同步原语可以做什么?

to be continued.

上一篇 下一篇

猜你喜欢

热点阅读