什么是内存屏障?为什么需要内存屏障?

1.什么是内存屏障?,为什么需要内存屏障?

首先,为了性能编译器和处理器都会对指令进行重排序。

什么是内存屏障:内存屏障是一条指令,该指令可以对编译器(软件)和处理器(硬件)的指令重排做出一定的限制,比如,一条内存屏障指令可以禁止编译器和处理器将其后面的指令移到内存屏障指令之前。

为什么需要内存屏障:编译器和处理器指令重排只能保证在单线程执行下逻辑正确,在多个线程同时读写多个变量的情况下,如果不对指令重排作出一定限制,代码的执行结果会根据指令重排后的顺序产生不同的结果。指令重排后的顺序每次执行时都可能不一样,显然我们希望我们的代码执行结果与代码顺序是逻辑一致的(可能不太准确),所以我们需要内存屏障。比如。

#define  DRINK_TEA        0#define  PASS_CLASSROOM  1#define  LEAVE_CLASSROOM  2std::atomic<int>teacher_state(DRINK_TEA);std::atomic<int>cat_state(DRINK_TEA);std::atomic<int>your_state;// thread1                                                                  teacher_state.store(PASS_CLASSROOM,std::memory_order_relaxed);// A      cat_state.store(PASS_CLASSROOM,std::memory_order_relaxed);// B// thread2if(cat_state.load(std::memory_order_relaxed)==PASS_CLASSROOM){your_state.store(LEAVE_CLASSROOM,std::memory_order_relaxed);}

std::memory_order_relaxed:表面该原子操作不携带任何内存屏障。

上面例子做的事情为:

thread1:首先老师经过教室,然后猫经过教室。

thread2:检查猫是否经过了教室,如果猫经过了教室,那你就逃课。

在指令不重排的情况下,是ok的。你逃课之后不会被老师发现(不鼓励-_-)。但是如果指令重排把B排在了A前面。当你发现猫经过教室的时候,你离开教室,然后老师经过教室。这显然是不期望发生的。所以我们可以把A改为:

teacher_state.store(PASS_CLASSROOM, std::memory_order_acquire); // A 

std::memory_order_acquire:表明A指令之后的读写指令都不可以重排到A指令之前。即B不会发生在A,那么就可以安全的逃课了。

2. 锁与原子操作

2.1 锁的实现

自旋锁实现伪代码:

classSpinLock{atomic<int>lock_state_(0);lock(){// step1. 对原子变量进行CAS操作intexpected=0;while(!lock_state_.compare_exchange_strong(expected,1,std::memory_order_acq_rel));// 获取锁成功// step2. 加上内存屏障指令,使得临界区的指令不会跑到临界区外面去__sync_synchronize();// 内存屏障指令,与编译器实现,不同平台指令不同。}unlock(){// step1. 加上内存屏障指令,使得临界区的指令不会跑到临界区外面去__sync_synchronize();// step2.将原子变量设置为0lock_state_=0;}};

互斥锁实现伪代码:

classSleepLock{bool_locked;SpinLock_spin_lock;lock(){_spin_lock.lock();while(_locked){sleep(&_spin_lock);// 1. 释放_spin_lock并陷入内核放弃cpu执行权// 2. 被唤醒时会重新获得_spin_lock}_locked=true;_spin_lock.unlock();}unlock(){_spin_lock.lock();_locked=false;wakeup(&_spin_lock);// 唤醒等待在该锁上的其他线程_spin_lock.unlock();}};

注释较为丰富,不做详细解释。

2.2 锁与原子操作的区别、关系

锁的实现依赖于原子操作指令

锁的实现需要内存屏障保证临界区指令不跑出临界区,该内存屏障为最严格的内存屏障,任何指令都不可以越过该内存屏障

自旋锁在获取锁的时候,如果获取失败会一直尝试,在锁竞争不严重时效率较高

互斥锁在获取锁失败的时候会sleep,陷入内核;在锁竞争严重是,线程会频繁在内核态与用户态切换,非常影响性能。

在使用锁时提高性能主要是两点:

减少锁竞争

缩小临界区

3. C++的6中memory order

6种memory order或者说成6种内存屏障。理论上只要有一种内存屏障就够了,即所有该内存屏障之前的指令不可以重排到内存屏障之后,所有该内存屏障之后的指令不可以排到内存屏障之前,但这种内存屏障太严格了,有时候部分指令越过内存屏障对逻辑正确性无影响,同时又能提高性能。针对这种情况,c++在原子变量的操作中提供了6中内存屏障供开发人员自由选择:

memory_order_relaxed: 无内存屏障语义,只保证该操作的原子性。

memory_order_consume:load方法使用该内存屏障,内存屏障后面的所有依赖该操作的指令都不可以重排到该内存屏障前面。```cppa.load(std::memory_order_consume);b=a;// 该指令依赖a的值,所以在该内存屏障语义下,不允许重排到该指令前面```

memory_order_acquire: load方法使用该内存屏障,比memory_order_consume更严格,内存屏障后面的所有读写指令都不可以重排到该内存屏障前面。

memory_order_release: store方法使用该内存屏障,内存屏障前面的所有读写指令都不可以重排到该内存屏障后面,经常像下面这样搭配使用。

线程1使用memory_order_release, 线程2使用 memory_order_acquire, 构成Release-Acquire ordering

线程1使用memory_order_release, 线程2使用 memory_order_consume, 构成Release-Consume ordering

memory_order_acq_rel:compare_exchange_strong等read-modify-write使用该内存屏障,同时具有memory_order_acquire 和 memory_order_release语义。

memory_order_seq_cst:load方法使用该内存屏障具有memory_order_acquire语义;store方法使用该内存屏障,具有memory_order_release语义。read-modify-write类型操作如(compare_exchange_strong)使用该内存屏障具有memory_order_acq_rel语义。

【文章福利】小生推荐自己的Linux后台/内核技术交流群【 318652197】整理了一些个人觉得比较好的学习书籍,视频资料共享在群文件里面,有需要的自行添加哦!!!前100名进群领取,额外赠送一份价值699的内核资料包(含视频、电子书、实战项目及代码)

资料免费领

学习直通车

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343