﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-右席的搬砖日记-随笔分类-搬砖之路</title><link>http://cppblog.com/pwq1989/category/20753.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 19 Jan 2016 13:44:52 GMT</lastBuildDate><pubDate>Tue, 19 Jan 2016 13:44:52 GMT</pubDate><ttl>60</ttl><item><title>记一次Memory Barrier相关的小栗子</title><link>http://www.cppblog.com/pwq1989/archive/2016/01/19/212688.html</link><dc:creator>右席</dc:creator><author>右席</author><pubDate>Tue, 19 Jan 2016 08:13:00 GMT</pubDate><guid>http://www.cppblog.com/pwq1989/archive/2016/01/19/212688.html</guid><wfw:comment>http://www.cppblog.com/pwq1989/comments/212688.html</wfw:comment><comments>http://www.cppblog.com/pwq1989/archive/2016/01/19/212688.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/pwq1989/comments/commentRss/212688.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwq1989/services/trackbacks/212688.html</trackback:ping><description><![CDATA[<h3>0x0</h3><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;">前些天组里老司机@梁希在jvm的项目榨干机器性能之余，为了检查下gcc编译器和Intel Xoen CPU的正确性，写了一组测试代码测试了下mfence指令的效果</p><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;">`<br style="box-sizing: border-box;" />mfence Opcode : 0F AE /6</p><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;">Performs a serializing operation on all load-from-memory and store-to-memory instructions that were issued prior the MFENCE instruction. This serializing operation guarantees that every load and store instruction that precedes in program order the MFENCE instruction is globally visible before any load or store instruction that follows the MFENCE instruction is globally visible. The MFENCE instruction is ordered with respect to all load and store instructions, other MFENCE instructions, any SFENCE and LFENCE instructions, and any serializing instructions (such as the CPUID instruction).<br style="box-sizing: border-box;" />Weakly ordered memory types can be used to achieve higher processor performance through such techniques as out-of-order issue, speculative reads, write-combining, and write-collapsing.<br style="box-sizing: border-box;" />The degree to which a consumer of data recognizes or knows that the data is weakly ordered varies among applications and may be unknown to the producer of this data. The MFENCE instruction provides a performance-efficient way of ensuring load and store ordering between routines that produce weakly-ordered results and routines that consume that data.<br style="box-sizing: border-box;" />It should be noted that processors are free to speculatively fetch and cache data from system memory regions that are assigned a memory-type that permits speculative reads (that is, the WB, WC, and WT memory types). The PREFETCHh instruction is considered a hint to this speculative behavior. Because this speculative fetching can occur at any time and is not tied to instruction execution, the MFENCE instruction is not ordered with respect to PREFETCHh instructions or any other speculative fetching mechanism (that is, data could be speculatively loaded into the cache just before, during, or after the execution of an MFENCE instruction).<br style="box-sizing: border-box;" />`</p><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;">简单来说就是一个可以在CPU乱序执行中保证真实的load/store顺序的指令<br /></p><h3 id="1" style="box-sizing: border-box; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-weight: 500; line-height: 1.1; color: #333333; margin-top: 30px; margin-bottom: 10px; font-size: 24px; border-bottom-width: 1px; border-bottom-style: dashed; border-bottom-color: #dddddd; background-color: #ffffff;">0x1<br /><span style="font-size: 16px; letter-spacing: 0.48px; line-height: 27.2px;">老司机写了一个小程序(注：有误版)</span><br /><span style="font-size: 13px; font-family: verdana, 'courier new'; line-height: 21px; color: #008000;">//</span><span style="font-size: 13px; font-family: verdana, 'courier new'; line-height: 21px; color: #008000;">&nbsp;file:&nbsp;order.c</span></h3><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><span style="color: #0000FF; ">#define</span>&nbsp;_GNU_SOURCE<br />#include&nbsp;&lt;pthread.h&gt;<br />#include&nbsp;&lt;stdio.h&gt;<br />#include&nbsp;&lt;stdlib.h&gt;<br />#include&nbsp;&lt;assert.h&gt;<br /><br />union&nbsp;p64&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;padding[64];<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">long</span>&nbsp;align8;<br />};<br /><br /><span style="color: #0000FF; ">volatile</span>&nbsp;union&nbsp;p64&nbsp;v1,&nbsp;v2;<br /><span style="color: #0000FF; ">int</span>&nbsp;b;<br /><br /><span style="color: #0000FF; ">void</span>&nbsp;*<br />run1(<span style="color: #0000FF; ">void</span>&nbsp;*ignore)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(;;)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(!b);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(v1.i&nbsp;||&nbsp;v2.i)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts("assert&nbsp;error&nbsp;1");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(-1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v1.i&nbsp;=&nbsp;1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;asm&nbsp;("sfence":&nbsp;:&nbsp;:"memory");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v2.i&nbsp;=&nbsp;1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;asm&nbsp;("sfence":&nbsp;:&nbsp;:"memory");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;=&nbsp;0;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}<br /><br /><span style="color: #0000FF; ">int</span><br />main()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;pthread_t&nbsp;p;<br />&nbsp;&nbsp;&nbsp;&nbsp;pthread_create(&amp;p,&nbsp;NULL,&nbsp;run1,&nbsp;NULL);<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;cnt&nbsp;=&nbsp;0;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(;;&nbsp;cnt++)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v1.i&nbsp;=&nbsp;v2.i&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;asm&nbsp;("sfence":&nbsp;:&nbsp;:"memory");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;=&nbsp;1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;asm&nbsp;("sfence":&nbsp;:&nbsp;:"memory");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;icnt&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(;;&nbsp;icnt++)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i1&nbsp;=&nbsp;v1.i;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;asm&nbsp;("lfence":&nbsp;:&nbsp;:"memory");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i2&nbsp;=&nbsp;v2.i;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(i1&nbsp;&amp;&amp;&nbsp;i2)&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">break</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(i1&nbsp;&lt;&nbsp;i2)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("assert&nbsp;error,&nbsp;cnt&nbsp;=&nbsp;%d,&nbsp;icnt&nbsp;=&nbsp;%d,&nbsp;i1&nbsp;=&nbsp;%d,&nbsp;i2&nbsp;=&nbsp;%d\n",&nbsp;cnt,&nbsp;icnt,&nbsp;i1,&nbsp;i2);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(-1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />}</div><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;">大概逻辑是： 一共有3个变量，<code style="box-sizing: border-box; font-size: 14.4px; border-radius: 2px; padding: 2px 4px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; color: #c7254e; white-space: nowrap; background-color: #f9f2f4;">v1.i</code>,&nbsp;<code style="box-sizing: border-box; font-size: 14.4px; border-radius: 2px; padding: 2px 4px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; color: #c7254e; white-space: nowrap; background-color: #f9f2f4;">v2.i</code>,&nbsp;<code style="box-sizing: border-box; font-size: 14.4px; border-radius: 2px; padding: 2px 4px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; color: #c7254e; white-space: nowrap; background-color: #f9f2f4;">b</code>&nbsp;,起了2个线程，一个顺序写入v1和v2，一个读v1和v2，互相通过改变b的值来通讯，然后两个线程不停循环。</p><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;">这个程序会挂在<br /><span style="font-family: verdana, 'courier new'; font-size: 14px; line-height: 21px;">printf("assert error, cnt = %d, icnt = %d, i1 = %d, i2 = %d\n", cnt, icnt, i1, i2);&nbsp;<br /></span><span style="letter-spacing: 0.36px; line-height: 27.2px;">这条断言上，意思是线程1在顺序写入v1和v2，但是主线程却出现读到 v1=0，v2=1的情况。<br /><br /></span></p><h3 id="2" style="box-sizing: border-box; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-weight: 500; line-height: 1.1; color: #333333; margin-top: 30px; margin-bottom: 10px; font-size: 24px; border-bottom-width: 1px; border-bottom-style: dashed; border-bottom-color: #dddddd; background-color: #ffffff;">0x2</h3><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;">然后我帮忙去看了一下，觉得这种写法甚是粗暴，于是原样照搬了一个c++11版:</p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#include&nbsp;&lt;stdio.h&gt;<br />#include&nbsp;&lt;stdlib.h&gt;<br />#include&nbsp;&lt;assert.h&gt;<br /><br />#include&nbsp;&lt;atomic&gt;<br />#include&nbsp;&lt;thread&gt;<br /><br /><span style="color: #0000FF; ">using</span>&nbsp;<span style="color: #0000FF; ">namespace</span>&nbsp;std;<br /><br />union&nbsp;p64&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;atomic&lt;<span style="color: #0000FF; ">int</span>&gt;&nbsp;i;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;padding[64];<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">long</span>&nbsp;align8;<br />};<br /><br /><span style="color: #0000FF; ">volatile</span>&nbsp;union&nbsp;p64&nbsp;v1,&nbsp;v2;<br />atomic&lt;<span style="color: #0000FF; ">int</span>&gt;&nbsp;b;<br /><br /><span style="color: #0000FF; ">void</span>&nbsp;*<br />run1()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;rcnt&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(;;&nbsp;rcnt++)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(!b.load());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(v1.i.load()&nbsp;||&nbsp;v2.i.load())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts("assert&nbsp;error&nbsp;1");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(-1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v1.i.store(1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v2.i.store(1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b.store(0);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}<br /><br /><span style="color: #0000FF; ">int</span><br />main()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;init</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;v1.i.store(0);<br />&nbsp;&nbsp;&nbsp;&nbsp;v2.i.store(0);<br />&nbsp;&nbsp;&nbsp;&nbsp;thread&nbsp;t(run1);<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;cnt&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(;;&nbsp;cnt++)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v1.i.store(0);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v2.i.store(0);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b.store(1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;icnt&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(;;&nbsp;icnt++)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;b2&nbsp;=&nbsp;b.load();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i1&nbsp;=&nbsp;v1.i.load();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;*****</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i2&nbsp;=&nbsp;v2.i.load();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;*****</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(i1&nbsp;&amp;&amp;&nbsp;i2)&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">break</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(i1&nbsp;&lt;&nbsp;i2)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("assert&nbsp;error,&nbsp;cnt&nbsp;=&nbsp;%d,&nbsp;icnt&nbsp;=&nbsp;%d,&nbsp;i1&nbsp;=&nbsp;%d,&nbsp;i2&nbsp;=&nbsp;%d\n",&nbsp;cnt,&nbsp;icnt,&nbsp;i1,&nbsp;i2);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(-1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(i1&nbsp;==&nbsp;0&nbsp;&amp;&amp;&nbsp;i2&nbsp;==&nbsp;0&nbsp;&amp;&amp;&nbsp;b2&nbsp;==&nbsp;0)&nbsp;<span style="color: #0000FF; ">break</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />}</div><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;">因为是原样照搬，所以肯定还是会挂，但是毕竟语义上更好理解了</p><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;">我们先来分析一下为什么会挂</p><ul style="box-sizing: border-box; margin-top: 0px; margin-bottom: 10px; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;"><li style="box-sizing: border-box; margin-top: 5px;">线程1对于v1，v2的写入顺序一定是一致的</li><li style="box-sizing: border-box; margin-top: 5px;">Memory Barrier也保证了他们写入顺序对其他线程的可见性（很有迷惑性的一点）</li><li style="box-sizing: border-box; margin-top: 5px;">但是主线程却可以读到 v1=0,v2=1的情况</li><li style="box-sizing: border-box; margin-top: 5px;">所以情况就是虽然顺序写入了，但是别的线程没有看到正确的顺序？</li><li style="box-sizing: border-box; margin-top: 5px;">Intel: 并不是！</li><li style="box-sizing: border-box; margin-top: 5px;">原因是搞错了因果关系，他真正保证的顺序是当你读到v2的new value的时候，那么v1也一定被写入了。</li><li style="box-sizing: border-box; margin-top: 5px;">解决方案就是互换上面代码中我用**星号**标注出的两行</li><li style="box-sizing: border-box; margin-top: 5px;">done</li></ul><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;">在旧写法中，挂掉的情况是线程1写入v1 = 1，主线程读v1，没有读到，那么主线程认为v1是0，然后线程1继续写入v2，主线程读到了，主线程认为v2是1。 然后挂在了断言上。</p><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;">两行互换后，主线程首先读取v2，如果v2已经是1了，那么v1也一定是1，反之亦然。</p><h3></h3><h3>0x3</h3><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;">当然，想让跑通那个例子不需要那么多的atomic&lt;&gt;，精简之后利用c++11的memory_order可以写成如下：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#include&nbsp;&lt;stdio.h&gt;<br />#include&nbsp;&lt;stdlib.h&gt;<br />#include&nbsp;&lt;assert.h&gt;<br /><br />#include&nbsp;&lt;atomic&gt;<br />#include&nbsp;&lt;thread&gt;<br /><br /><span style="color: #0000FF; ">using</span>&nbsp;<span style="color: #0000FF; ">namespace</span>&nbsp;std;<br /><br />union&nbsp;p64&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;padding[64];<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">long</span>&nbsp;align8;<br />};<br /><br /><span style="color: #0000FF; ">volatile</span>&nbsp;union&nbsp;p64&nbsp;v1,&nbsp;v2;<br />atomic&lt;<span style="color: #0000FF; ">int</span>&gt;&nbsp;b;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;variable&nbsp;b&nbsp;as&nbsp;a&nbsp;guard</span><span style="color: #008000; "><br /></span><br /><span style="color: #0000FF; ">void</span>&nbsp;*<br />run1()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;rcnt&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(;;&nbsp;rcnt++)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(!b.load());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(v1.i&nbsp;||&nbsp;v2.i)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts("assert&nbsp;error&nbsp;1");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(-1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v1.i&nbsp;=&nbsp;1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v2.i&nbsp;=&nbsp;1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b.store(0,&nbsp;memory_order_release);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}<br /><span style="color: #0000FF; ">int</span><br />main()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;init</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;v1.i&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;v2.i&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;thread&nbsp;t(run1);<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;cnt&nbsp;=&nbsp;0;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(;;&nbsp;cnt++)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v1.i&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v2.i&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b.store(1,&nbsp;memory_order_release);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;icnt&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(;;&nbsp;icnt++)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;b2&nbsp;=&nbsp;b.load(memory_order_acquire);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(b2&nbsp;!=&nbsp;0)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">continue</span>;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i1&nbsp;=&nbsp;v1.i;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i2&nbsp;=&nbsp;v2.i;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(i1&nbsp;&amp;&amp;&nbsp;i2)&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">break</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(i1&nbsp;&lt;&nbsp;i2)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("assert&nbsp;error&nbsp;2,&nbsp;cnt&nbsp;=&nbsp;%d,&nbsp;icnt&nbsp;=&nbsp;&nbsp;%d,&nbsp;i1&nbsp;=&nbsp;%d,&nbsp;i2&nbsp;=&nbsp;%d\n",&nbsp;cnt,&nbsp;icnt,&nbsp;i1,&nbsp;i2);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(-1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />}</div><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;"><span style="letter-spacing: 0.36px; line-height: 27.2px;">利用变量b在两个线程之间同步，如下图<br /></span></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->&nbsp;(Thead&nbsp;1)<br /><br />&nbsp;&nbsp;&nbsp;v1.i&nbsp;=&nbsp;1;<br />&nbsp;&nbsp;&nbsp;v2.i&nbsp;=&nbsp;1;<br />&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br />&nbsp;&nbsp;&nbsp;b.store(0,&nbsp;memory_order_release)&nbsp;&lt;---+<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; synchronize&nbsp;with&nbsp;b<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(happend&nbsp;before)<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;+-----&gt;&nbsp;&nbsp;b.load(memory_order_acquire)<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i1&nbsp;=&nbsp;v1.i<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i2&nbsp;=&nbsp;v2.i<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(Thread&nbsp;2)</div><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;"><span style="letter-spacing: 0.36px; line-height: 27.2px;">我们查看下生成的代码</span><br style="box-sizing: border-box; letter-spacing: 0.36px; line-height: 27.2px;" /><code style="box-sizing: border-box; font-size: 14.4px; border-radius: 2px; padding: 2px 4px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; color: #c7254e; white-space: nowrap; letter-spacing: 0.36px; background-color: #f9f2f4;">g++ -std=c++11 -pthread -g -O2 order.cpp</code><br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->&nbsp;v1.i&nbsp;=&nbsp;1;<br />&nbsp;&nbsp;400be6:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c7&nbsp;05&nbsp;d0&nbsp;10&nbsp;20&nbsp;00&nbsp;01&nbsp;&nbsp;&nbsp;&nbsp;movl&nbsp;&nbsp;&nbsp;$0x1,0x2010d0(%rip)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;601cc0&nbsp;&lt;v1&gt;<br />&nbsp;&nbsp;400bed:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;00&nbsp;00&nbsp;00&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v2.i&nbsp;=&nbsp;1;<br />&nbsp;&nbsp;400bf0:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c7&nbsp;05&nbsp;86&nbsp;10&nbsp;20&nbsp;00&nbsp;01&nbsp;&nbsp;&nbsp;&nbsp;movl&nbsp;&nbsp;&nbsp;$0x1,0x201086(%rip)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;601c80&nbsp;&lt;v2&gt;<br />&nbsp;&nbsp;400bf7:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;00&nbsp;00&nbsp;00&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memory_order&nbsp;__b&nbsp;=&nbsp;__m&nbsp;&amp;&nbsp;__memory_order_mask;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__glibcxx_assert(__b&nbsp;!=&nbsp;memory_order_acquire);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__glibcxx_assert(__b&nbsp;!=&nbsp;memory_order_acq_rel);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__glibcxx_assert(__b&nbsp;!=&nbsp;memory_order_consume);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__atomic_store_n(&amp;_M_i,&nbsp;__i,&nbsp;__m);<br />&nbsp;&nbsp;400bfa:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c7&nbsp;05&nbsp;5c&nbsp;10&nbsp;20&nbsp;00&nbsp;00&nbsp;&nbsp;&nbsp;&nbsp;movl&nbsp;&nbsp;&nbsp;$0x0,0x20105c(%rip)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;601c60&nbsp;&lt;b&gt;<br />&nbsp;&nbsp;400c01:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;00&nbsp;00&nbsp;00&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b.store(0,&nbsp;memory_order_release);<br /><br />&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br /><br />&nbsp;&nbsp;400a58:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8b&nbsp;05&nbsp;02&nbsp;12&nbsp;20&nbsp;00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;0x201202(%rip),%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;601c60&nbsp;&lt;b&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;b2&nbsp;=&nbsp;b.load(memory_order_consume);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(b2&nbsp;!=&nbsp;0)&nbsp;{<br />&nbsp;&nbsp;400a5e:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;85&nbsp;c0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;test&nbsp;&nbsp;&nbsp;%eax,%eax<br />&nbsp;&nbsp;400a60:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;75&nbsp;f3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jne&nbsp;&nbsp;&nbsp;&nbsp;400a55&nbsp;&lt;main+0x55&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">continue</span>;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i1&nbsp;=&nbsp;v1.i;<br />&nbsp;&nbsp;400a62:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8b&nbsp;0d&nbsp;58&nbsp;12&nbsp;20&nbsp;00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;0x201258(%rip),%ecx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;601cc0&nbsp;&lt;v1&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i2&nbsp;=&nbsp;v2.i;<br />&nbsp;&nbsp;400a68:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;44&nbsp;8b&nbsp;05&nbsp;11&nbsp;12&nbsp;20&nbsp;00&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;0x201211(%rip),%r8d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;601c80&nbsp;&lt;v2&gt;</div><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;">看来Intel的Strong Memory Model已经保证了这一点，Memory Barrier都不需要了</p><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;">（虽然标题里面有MemoryBarrier，但是内容里面根本没涉及的样子。。）</p><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16px; line-height: 27.2px; background-color: #ffffff;"></p><img src ="http://www.cppblog.com/pwq1989/aggbug/212688.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwq1989/" target="_blank">右席</a> 2016-01-19 16:13 <a href="http://www.cppblog.com/pwq1989/archive/2016/01/19/212688.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>函数式编程语言与副作用</title><link>http://www.cppblog.com/pwq1989/archive/2014/07/10/207540.html</link><dc:creator>右席</dc:creator><author>右席</author><pubDate>Thu, 10 Jul 2014 07:16:00 GMT</pubDate><guid>http://www.cppblog.com/pwq1989/archive/2014/07/10/207540.html</guid><wfw:comment>http://www.cppblog.com/pwq1989/comments/207540.html</wfw:comment><comments>http://www.cppblog.com/pwq1989/archive/2014/07/10/207540.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/pwq1989/comments/commentRss/207540.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwq1989/services/trackbacks/207540.html</trackback:ping><description><![CDATA[<div><br /><h3>序</h3><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16.3636360168457px; line-height: 24.7272720336914px; background-color: #ffffff;">函数式编程语言有很多种定义，宽泛的认为支持高阶函数（higher-order function）就算函数式语言的话，大多数现代语言都是支持函数式编程的，例如C/C++，java，C#，lua，python，JavaScript，Scala等等。收紧一下定义的话，加入函数式语言要求的模式匹配、无副作用等要求，那么剩下的就是纯函数式语言，比较常见的有Haskell，Clean等。</p><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16.3636360168457px; line-height: 24.7272720336914px; background-color: #ffffff;">副作用是什么和为什么有些语言想在设计上避免副作用这个问题，google能搜出好多博文，这里就不多说了。避免副作用可以带来一些实际的好处，比如帮你大量改写代码什么的（误），而且连gcc都有 _ _ attribute _ _((pure/const))的函数扩展嘛~。比如像erlang这种依赖于副作用编程的语言，虽然有着变量不可变这个特性，但是仍然可以读写process携带的全局变量，而且又没有一个好的类型系统，所以在编译的时候也不会怎么大改你的代码，大多还是直译成字节码。</p><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16.3636360168457px; line-height: 24.7272720336914px; background-color: #ffffff;"><span style="box-sizing: border-box; font-weight: 700;">注：</span>这篇文章不是**软文**，不会用个g(f(x))就当例子给大家说无副作用多么多么好，可缓存结果拉(just a lie)~原生支持并行拉(just another lie)，这些都是扯淡而且不实际的。（有机会再写个博客专门谈谈这个）</p><h3>正文</h3><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16.3636360168457px; line-height: 24.7272720336914px; background-color: #ffffff;">首先，纯函数式的语言强调没有副作用，它不会改变任何实际的东西，当然也没有（全局的）状态，这样的程序如果不配上代表副作用的输入输出当然是什么都干不了的。那么如何把副作用嵌入到本不该有副作用的语言设计中那？当然不能直接赋值，不然。。不然。。就变成命令式语言了，而且函数式语言编译中引以为豪的各种优化pass几乎都不能用了。那么把有副作用的函数标注出来？当然是一个办法。还有就是把副作用的表达式都包含在context中，随着函数传递，保证顺序而且要保证引用的唯一性。</p><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16.3636360168457px; line-height: 24.7272720336914px; background-color: #ffffff;">作为纯函数式语言的代表，Haskell和Clean对于副作用的设计实现上差别很大，下面就简单说一下它们的实现，刨根究底，其实它们做的还是同一件事情。</p><h4>haskell</h4><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16.3636360168457px; line-height: 24.7272720336914px; background-color: #ffffff;">Haskell中有一个很重要的概念：Monad，取名自范畴论，可以粗浅的认为它就是定义了一系列的行为准则（&gt;&gt;= , return）。Haskell中大多数语法糖都是为了这个发明来的。Haskell的标准库中有很多关于副作用的类库封装，比如IORef，MVar，IOMonad等等，他们的内部实现都会归结到ST Monad（State Thread Monad）上，正是这个与forall关键字的结合，从而在语法上保证了副作用嵌入在（纯）Haskell中的正确性。<br style="box-sizing: border-box;" />ST Monad里面主要的定义是：</p><pre style="box-sizing: border-box; overflow: auto; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; padding: 0px; margin-top: 0px; margin-bottom: 10px; line-height: 1.42857143; word-break: break-all; word-wrap: break-word; color: #333333; border: 0px; border-radius: 2px; background-color: #f5f5f5;"><code data-language="js"  haskell"="" style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: inherit; padding: 0.5em; color: #f8f8f2; white-space: pre-wrap; border-radius: 0px; display: block; overflow-x: auto; background: #23241f;"> <span class="hljs-typedef" style="box-sizing: border-box; font-size: 12.7272720336914px; line-height: 16.8831157684326px;"><span class="hljs-keyword" style="box-sizing: border-box; color: #f92672;">newtype</span> <span class="hljs-type" style="box-sizing: border-box; color: #e6db74;">ST</span> s a = <span class="hljs-type" style="box-sizing: border-box; color: #e6db74;">ST</span> <span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-type" style="box-sizing: border-box; color: #e6db74;">STRep</span> <span class="hljs-title" style="box-sizing: border-box; color: #a6e22e;">s</span> <span class="hljs-title" style="box-sizing: border-box; color: #a6e22e;">a</span>)</span></span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">
 </span><span class="hljs-typedef" style="box-sizing: border-box; font-size: 12.7272720336914px; line-height: 16.8831157684326px;"><span class="hljs-keyword" style="box-sizing: border-box; color: #f92672;">type</span> <span class="hljs-type" style="box-sizing: border-box; color: #e6db74;">STRep</span> s a = <span class="hljs-type" style="box-sizing: border-box; color: #e6db74;">State</span># s -&gt; <span class="hljs-container" style="box-sizing: border-box;">(# <span class="hljs-type" style="box-sizing: border-box; color: #e6db74;">State</span># <span class="hljs-title" style="box-sizing: border-box; color: #a6e22e;">s</span>, <span class="hljs-title" style="box-sizing: border-box; color: #a6e22e;">a</span> #)</span></span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">
 </span><span class="hljs-typedef" style="box-sizing: border-box; font-size: 12.7272720336914px; line-height: 16.8831157684326px;"><span class="hljs-keyword" style="box-sizing: border-box; color: #f92672;">data</span> <span class="hljs-type" style="box-sizing: border-box; color: #e6db74;">STRef</span> s a = <span class="hljs-type" style="box-sizing: border-box; color: #e6db74;">STRef</span> <span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-type" style="box-sizing: border-box; color: #e6db74;">MutVar</span># <span class="hljs-title" style="box-sizing: border-box; color: #a6e22e;">s</span> <span class="hljs-title" style="box-sizing: border-box; color: #a6e22e;">a</span>)</span></span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">

 runST :: (</span><span class="hljs-keyword" style="box-sizing: border-box; color: #f92672; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">forall</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;"> s. </span><span class="hljs-type" style="box-sizing: border-box; color: #e6db74; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">ST</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;"> s a) -&gt; a
 runSTRep :: (</span><span class="hljs-keyword" style="box-sizing: border-box; color: #f92672; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">forall</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;"> s. </span><span class="hljs-type" style="box-sizing: border-box; color: #e6db74; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">STRep</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;"> s a) -&gt; a</span><br /> </code></pre><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16.3636360168457px; line-height: 24.7272720336914px; background-color: #ffffff;">其中最关键的是ST s a 与 STref s a 这两个数据结构。</p><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16.3636360168457px; line-height: 24.7272720336914px; background-color: #ffffff;">先看看这个用法，<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 14.5454540252686px; padding: 2px 4px; color: #c7254e; white-space: nowrap; border-radius: 2px; background-color: #f9f2f4;">let a0 = runST $ newSTRef 0</code>，会引发一个type error。因为runST的类型是<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 14.5454540252686px; padding: 2px 4px; color: #c7254e; white-space: nowrap; border-radius: 2px; background-color: #f9f2f4;">(forall s.ST s a) -&gt; a</code>&nbsp;，参数<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 14.5454540252686px; padding: 2px 4px; color: #c7254e; white-space: nowrap; border-radius: 2px; background-color: #f9f2f4;">(newSTRef 0)</code>的类型是<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 14.5454540252686px; padding: 2px 4px; color: #c7254e; white-space: nowrap; border-radius: 2px; background-color: #f9f2f4;">forall s. ST s (STRef s Int)</code>，最后求值后的结果是<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 14.5454540252686px; padding: 2px 4px; color: #c7254e; white-space: nowrap; border-radius: 2px; background-color: #f9f2f4;">a0::STRef s Int</code>，显然s脱离了原本的定义域（也就是那层forall之外，forall是Haskell中提供**RankNType**的关键字）。从而用户就只能使用下面的方式：</p><pre style="box-sizing: border-box; overflow: auto; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; padding: 0px; margin-top: 0px; margin-bottom: 10px; line-height: 1.42857143; word-break: break-all; word-wrap: break-word; color: #333333; border: 0px; border-radius: 2px; background-color: #f5f5f5;"><code data-language="js"  elixir"="" style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: inherit; padding: 0.5em; color: #f8f8f2; white-space: pre-wrap; border-radius: 0px; display: block; overflow-x: auto; background: #23241f;"><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">sumST </span><span class="hljs-symbol" style="box-sizing: border-box; color: #f92672; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">:</span><span class="hljs-symbol" style="box-sizing: border-box; color: #f92672; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">:</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;"> </span><span class="hljs-constant" style="box-sizing: border-box; color: #66d9ef; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">Num </span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">a =&gt; [a] -&gt; a
sumST xs = runST </span><span class="hljs-variable" style="box-sizing: border-box; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">$ </span><span class="hljs-keyword" style="box-sizing: border-box; color: #f92672; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">do</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">          
    n &lt;- newSTRef </span><span class="hljs-number" style="box-sizing: border-box; color: #ae81ff; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">0</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">             
    forM</span><span class="hljs-constant" style="box-sizing: border-box; color: #66d9ef; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">_</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;"> xs </span><span class="hljs-variable" style="box-sizing: border-box; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">$ </span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">\x -&gt; </span><span class="hljs-keyword" style="box-sizing: border-box; color: #f92672; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">do</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">        
    modifySTRef n (+x)     
    readSTRef n </span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">    </span></code></pre><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16.3636360168457px; line-height: 24.7272720336914px; background-color: #ffffff;">不用标出标出具体实现，大家就能看出他做的事情就是做了一层wrapper，在type checker上保证被box之后不会被用户取出来乱改。至于如何做到destructive in-place update，这就属于编译器的黑魔法了，语言这层只需保证语义就好。（**注：**ghc的实现中，ST Monad标准库用到了ghc的unsafe打头的内置函数）</p><h4>Clean</h4><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16.3636360168457px; line-height: 24.7272720336914px; background-color: #ffffff;">Clean语言用的策略是线性类型系统（linear type system），是Substructural type sysytem的一种。在Curry-Howard同构中对应Substructrual logic。这类类型系统中，不但可以决定一个变量是什么类型，还可以约束被使用的次数与顺序。在Mozilla出的Rust语言中，也可以看到线性类型的影子。</p><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16.3636360168457px; line-height: 24.7272720336914px; background-color: #ffffff;">先举个栗子~</p><pre style="box-sizing: border-box; overflow: auto; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; padding: 0px; margin-top: 0px; margin-bottom: 10px; line-height: 1.42857143; word-break: break-all; word-wrap: break-word; color: #333333; border: 0px; border-radius: 2px; background-color: #f5f5f5;"><code data-language="js"  gradle"="" style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: inherit; padding: 0.5em; color: #f8f8f2; white-space: pre-wrap; border-radius: 0px; display: block; overflow-x: auto; background: #23241f;"><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">transform :: (</span><span style="box-sizing: border-box; color: #f92672; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">Int</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;"> -&gt; </span><span style="box-sizing: border-box; color: #f92672; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">Int</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">) *{#</span><span style="box-sizing: border-box; color: #f92672; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">Int</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">} -&gt; *{#</span><span style="box-sizing: border-box; color: #f92672; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">Int</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">} <br /></span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">transform f s
 | </span><span class="hljs-keyword" style="box-sizing: border-box; color: #f92672; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">size</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;"> s == </span><span class="hljs-number" style="box-sizing: border-box; color: #ae81ff; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">0</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;"> = s
 | otherwise   = </span><span class="hljs-keyword" style="box-sizing: border-box; color: #f92672; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">if</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;"> (s.[</span><span class="hljs-number" style="box-sizing: border-box; color: #ae81ff; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">0</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">] == </span><span class="hljs-number" style="box-sizing: border-box; color: #ae81ff; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">0</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">)
                   {f i \\ i &lt;-: s}
                   {f i \\ _ &lt;-: s &amp; i &lt;- [s.[</span><span class="hljs-number" style="box-sizing: border-box; color: #ae81ff; font-size: 12.7272720336914px; line-height: 16.8831157684326px;">0</span><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;">]..]}</span><br /><span style="font-size: 12.7272720336914px; line-height: 16.8831157684326px;"><br /></span></code></pre><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16.3636360168457px; line-height: 24.7272720336914px; background-color: #ffffff;">（不要在意奇怪的语法，｛｝里面其实就是list comprehension）</p><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16.3636360168457px; line-height: 24.7272720336914px; background-color: #ffffff;">其中*就是uniqueness type的标注，这个函数的类型用haskell写出来就是<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 14.5454540252686px; padding: 2px 4px; color: #c7254e; white-space: nowrap; border-radius: 2px; background-color: #f9f2f4;">transform :: (Int -&gt; Int) -&gt; *[Int] -&gt; *[Int]</code>。这个函数虽然没有很好的看出uniqueness type的特性和传播性，但是作为简单的例子，差不多就是这么回事。<br style="box-sizing: border-box;" />对于uniqueness type最直观的理解就是带有这个标识的类型是不能参与到以后Graph Reduction中，而且会检测会不会有多个&#8220;变量&#8221;指向他。上面这个函数中就不会存在多个[Int]及相关的副本等着被回收，而是会直接在（ReadWorld中的）内存上更新数据。</p><h3>最后</h3><p style="box-sizing: border-box; margin: 20px 0px; letter-spacing: 0.03rem; color: #333333; font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; font-size: 16.3636360168457px; line-height: 24.7272720336914px; background-color: #ffffff;">其实已经看出，在上面Haskell与Clean的做法中，一个是利用forall关键字与ST Monad+编译器黑魔法，另一个是build-in在类型系统中，但是本质都是做了一件事情，就是保证RealWorld中的对象不会存在多个引用，而且在Graph Reduction中不会被编译器搞乱顺序，这样就能融入到整个纯函数式的大体系中了。</p></div><br />本人博客地址（http://www.cppblog.com/pwq1989/）<br /><img src ="http://www.cppblog.com/pwq1989/aggbug/207540.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwq1989/" target="_blank">右席</a> 2014-07-10 15:16 <a href="http://www.cppblog.com/pwq1989/archive/2014/07/10/207540.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>类型系统与图灵完全</title><link>http://www.cppblog.com/pwq1989/archive/2014/07/10/207536.html</link><dc:creator>右席</dc:creator><author>右席</author><pubDate>Thu, 10 Jul 2014 07:14:00 GMT</pubDate><guid>http://www.cppblog.com/pwq1989/archive/2014/07/10/207536.html</guid><wfw:comment>http://www.cppblog.com/pwq1989/comments/207536.html</wfw:comment><comments>http://www.cppblog.com/pwq1989/archive/2014/07/10/207536.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/pwq1989/comments/commentRss/207536.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwq1989/services/trackbacks/207536.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 序类型系统在编程语言中是极为重要，不单单是提供一个类型的标注或是方便编译，更多时候是减少出错的可能。当类型系统强大到一定程度，就可以进行所谓的&#8220;富类型编程&#8221;，比如在Haskell中只要编译器不报错，大致上程序也是没什么bug的。在常用的静态类型语言中，C++/java/C#等，虽然在新标准与新版本中支持类型的自动推导，但是对类型系统及其推导还是缺少更为直接的支持。很多常用语...&nbsp;&nbsp;<a href='http://www.cppblog.com/pwq1989/archive/2014/07/10/207536.html'>阅读全文</a><img src ="http://www.cppblog.com/pwq1989/aggbug/207536.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwq1989/" target="_blank">右席</a> 2014-07-10 15:14 <a href="http://www.cppblog.com/pwq1989/archive/2014/07/10/207536.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Haskell别扭的Y-Combinator</title><link>http://www.cppblog.com/pwq1989/archive/2014/02/27/205964.html</link><dc:creator>右席</dc:creator><author>右席</author><pubDate>Wed, 26 Feb 2014 16:25:00 GMT</pubDate><guid>http://www.cppblog.com/pwq1989/archive/2014/02/27/205964.html</guid><wfw:comment>http://www.cppblog.com/pwq1989/comments/205964.html</wfw:comment><comments>http://www.cppblog.com/pwq1989/archive/2014/02/27/205964.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/pwq1989/comments/commentRss/205964.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwq1989/services/trackbacks/205964.html</trackback:ping><description><![CDATA[本人博客地址：http://www.cppblog.com/pwq1989/&nbsp;<br /><br />昨天在知乎上看到一个评论提到了Haskell的YC实现，就去搜了一下，然后就看到了一个实现：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">1</span>&nbsp;newtype&nbsp;Mu&nbsp;a&nbsp;=&nbsp;Mu&nbsp;(Mu&nbsp;a&nbsp;-&gt;&nbsp;a)<br /><span style="color: #008080; ">2</span>&nbsp;<br /><span style="color: #008080; ">3</span>&nbsp;y&nbsp;::&nbsp;(a&nbsp;-&gt;&nbsp;a)&nbsp;-&gt;&nbsp;a<br /><span style="color: #008080; ">4</span>&nbsp;y&nbsp;f&nbsp;=&nbsp;(\h&nbsp;-&gt;&nbsp;h&nbsp;$&nbsp;Mu&nbsp;h)&nbsp;(\x&nbsp;-&gt;&nbsp;f&nbsp;.&nbsp;(\(Mu&nbsp;g)&nbsp;-&gt;&nbsp;g)&nbsp;x&nbsp;$&nbsp;x)</div><br />嗯，真是别扭<br /><br />反观一下其他语言的YC写法，就贴一个lua的把<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">1</span>&nbsp;Y&nbsp;=&nbsp;<span style="color: #0000FF; ">function</span>&nbsp;(f)<br /><span style="color: #008080; ">2</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;<span style="color: #0000FF; ">function</span>(<img src="http://www.cppblog.com/Images/dot.gif" alt="" />)<br /><span style="color: #008080; ">3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;(<span style="color: #0000FF; ">function</span>(x)&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;x(x)&nbsp;end)<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(<span style="color: #0000FF; ">function</span>(x)&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;f(<span style="color: #0000FF; ">function</span>(y)&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;x(x)(y)&nbsp;end)&nbsp;end)(<img src="http://www.cppblog.com/Images/dot.gif" alt="" />)<br /><span style="color: #008080; ">4</span>&nbsp;&nbsp;&nbsp;&nbsp;end<br /><span style="color: #008080; ">5</span>&nbsp;end</div>虽然看起来很长，但是容易理解的多，用<span style="color: #444444; font-family: arial, sans-serif; font-size: small; line-height: 16.1200008392334px; background-color: #ffffff;">&#955;表达式写出来就是（<a href="http://en.wikipedia.org/wiki/Fixed-point_combinator#Y_combinator" target="_blank" title="wiki">wiki</a>）<br /></span><span style="color: #444444; font-family: arial, sans-serif; font-size: small; line-height: 16.1200008392334px; background-color: #ffffff;">&#955;f. (</span><span style="color: #444444; font-family: arial, sans-serif; font-size: small; line-height: 16.1200008392334px; background-color: #ffffff;">&#955;x. f (x x)) (</span><span style="color: #444444; font-family: arial, sans-serif; font-size: small; line-height: 16.1200008392334px; background-color: #ffffff;">&#955;x. f (x x))<br /></span>目的就是能做出 Y f = f (Y f) 这种效果，之所以这么写，是为了不引入名字（引入了名字是恶!）<br /><br />对于Haskell这种用HM类型系统的语言来说，最大的问题就是不能递归的定义类型，同样是静态类型检查，比如C#，就可以不费力的用Func和delegate做出来，haskell 额，就得扭曲的利用newtype Mu a = Mu (Mu a -&gt; a) 来绕过类型检查（当然，这个在Haskell中是不可能构造出一个实际的值的）。<br /><br />看下他是怎么做的，我们来把他展开一下：<br />原式子：y f = (\h -&gt; h $ Mu h) (\x -&gt; f . (\(Mu g) -&gt; g) x $ x)<br />带进去：y f = (\x -&gt; f . (\(Mu g) -&gt; g) x $ x) $ Mu (\x -&gt; f . (\(Mu g) -&gt; g) x $ x)<br />再来一遍：y f = f . (\x -&gt; f . (\(Mu g) -&gt; g) x $ x) $ Mu (\x -&gt; f . (\(Mu g) -&gt; g) x $ x)<br /><br />这样子，最后那个式子的f. 后面的那部分，提取&nbsp;(\x -&gt; f . (\(Mu g) -&gt; g) x $ x) 这个公因式 就相当于是(\h -&gt; h $ Mu h) (\x -&gt; f . (\(Mu g) -&gt; g) x $ x)了（很像数学把，但也没多大关系）<br />最后，就可以做出y f = f . (y f)了。<br /><br />其实这个写法最关键的是 newtype Mu a = Mu (Mu a -&gt; a)的作用，他是如何绕过类型检查，但是又不在运行期构造一个值（想构造也构造不出来）。<br /><br />来看下他的类型推导过程，y的类型是y :: (a -&gt; a) -&gt; a，所以里面f就是 f :: a -&gt; a，所以f . (\(Mu g) -&gt; g) x $ x 这个式子可以推出里面的x是 x :: Mu a 然后(\(Mu g) -&gt; g) x 取出里面的 a，这样就成了<br />f <span style="color: red;">a</span> $ Mu a，这时候Mu a = Mu (Mu a -&gt; a) 递归定义的作用就发挥了，为了类型的推导，继续将那个红色的a 推导成 Mu a -&gt; a，这样 f (Mu a -&gt; a) 会返回一个Mu a -&gt; a，管他叫f'把，这样 f' (Mu a) 就返回一个 a。有根据前面的(\h -&gt; h $ Mu h) 继续讲上面提到的a变成 Mu a -&gt; a。就是把Mu a 喂给了 (Mu a -&gt; a)，最后还是返回一个a。<br /><span style="font-size: 8pt;">(</span><span style="font-size: 8pt;">&gt;_&lt; 其实上面这段是我编出来的，我编不下去了，我不知道ghc是怎么做这个事情的，等我有生之年看完slpj-book-1987再想想)</span><br /><br />我们来应用一下，返回一个阶乘：<br /><div>y (\f n -&gt; if n &lt;= 1 then 1 else n * f (n - 1)) 5。 <br />不难看出，最终y的类型被特化成了 ((Int -&gt; Int) -&gt; (Int -&gt; Int)) -&gt; (Int -&gt; Int)</div><img src ="http://www.cppblog.com/pwq1989/aggbug/205964.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwq1989/" target="_blank">右席</a> 2014-02-27 00:25 <a href="http://www.cppblog.com/pwq1989/archive/2014/02/27/205964.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ 之 Memory Barrier </title><link>http://www.cppblog.com/pwq1989/archive/2014/01/08/205228.html</link><dc:creator>右席</dc:creator><author>右席</author><pubDate>Tue, 07 Jan 2014 16:54:00 GMT</pubDate><guid>http://www.cppblog.com/pwq1989/archive/2014/01/08/205228.html</guid><wfw:comment>http://www.cppblog.com/pwq1989/comments/205228.html</wfw:comment><comments>http://www.cppblog.com/pwq1989/archive/2014/01/08/205228.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/pwq1989/comments/commentRss/205228.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwq1989/services/trackbacks/205228.html</trackback:ping><description><![CDATA[本人博客地址：<a href="http://www.cppblog.com/pwq1989/">http://www.cppblog.com/pwq1989/</a>&nbsp;<br /><br /><br />今天群里姐夫推荐了个C++的Actor框架 Theron，就看了下源码，注释比代码还多，业界良心。<br /><br />源码我还没看完，就看到了他的一个叫StringPool的类，里面通过Ref来生成单例（Singleton），看了下<br /><div>static void Reference();这个函数实现的时候，突然脑洞一开，为啥没有Memory Barrier(<a href="http://en.wikipedia.org/wiki/Memory_barrier" target="_blank" title="wiki">wiki</a>)。<br /><br />先贴一下他的代码：</div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;StringPool&nbsp;*StringPool::smInstance&nbsp;=&nbsp;0;<br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;Mutex&nbsp;StringPool::smReferenceMutex;<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;uint32_t&nbsp;StringPool::smReferenceCount&nbsp;=&nbsp;0;<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;StringPool::Reference()<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;{<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp; &nbsp; &nbsp;Lock&nbsp;<span style="color: #0000FF; ">lock</span>(smReferenceMutex);<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Create&nbsp;the&nbsp;singleton&nbsp;instance&nbsp;if&nbsp;this&nbsp;is&nbsp;the&nbsp;first&nbsp;reference.</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(smReferenceCount++&nbsp;==&nbsp;0)<br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IAllocator&nbsp;*<span style="color: #0000FF; ">const</span>&nbsp;allocator(AllocatorManager::GetCache());<br /><span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;*<span style="color: #0000FF; ">const</span>&nbsp;memory(allocator-&gt;AllocateAligned(<span style="color: #0000FF; ">sizeof</span>(StringPool),&nbsp;THERON_CACHELINE_ALIGNMENT));<br /><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;smInstance&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;(memory)&nbsp;StringPool();<br /><span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">17</span>&nbsp;}</div><br />我们先不讨论这一段代码，先看看下面的：<br /><br />大家如果看过C++的Double Check Lock不可靠的这篇paper(<a href="http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf" target="_blank" title="地址">地址</a>)，作者给出的解决方案是这样的：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;&nbsp; &nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;First&nbsp;check</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;TYPE*&nbsp;tmp&nbsp;=&nbsp;instance_;<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Insert&nbsp;the&nbsp;CPU-specific&nbsp;memory&nbsp;barrier&nbsp;instruction<br /></span><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;to&nbsp;synchronize&nbsp;the&nbsp;cache&nbsp;lines&nbsp;on&nbsp;multi-processor.</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;5</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;asm&nbsp;("memoryBarrier");<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(tmp&nbsp;==&nbsp;0)&nbsp;{<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Ensure&nbsp;serialization&nbsp;(guard<br /></span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;constructor&nbsp;acquires&nbsp;lock_).</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Guard&lt;LOCK&gt;&nbsp;guard&nbsp;(lock_);<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Double&nbsp;check.</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tmp&nbsp;=&nbsp;instance_;<br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(tmp&nbsp;==&nbsp;0)&nbsp;{<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tmp&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;TYPE;<br /><span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Insert&nbsp;the&nbsp;CPU-specific&nbsp;memory&nbsp;barrier&nbsp;instruction<br /></span><span style="color: #008080; ">15</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;to&nbsp;synchronize&nbsp;the&nbsp;cache&nbsp;lines&nbsp;on&nbsp;multi-processor.</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">16</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;asm&nbsp;("memoryBarrier");<br /><span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;instance_&nbsp;=&nbsp;tmp;<br /><span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;tmp;</div><br />其实这两个Memory Barrier不用全屏障，第一个用读屏障rmb()就好了。第二个需要一个写屏障wmb()。<br /><br />我们都知道mb这个东西是为了防止CPU级别的指令乱序被发明出来的，（另一个是编译器级别的，和本篇文章没有多大关系，有兴趣大家可以去研究下），实现也是由平台相关的特殊指令(mfence这样的)组成的。<br /><br />之所以要写成这样，第二个mb()是为了防止在构造函数完成之前提前对目标赋值，但ctor还没完成，就被挂起，然后第二个线程访问的时候，认为已经构造完毕，进而使用不完整的数据引发奇怪的错误。<br /><br />(第一个rmb()的作用我觉得是可有可无，加上可能是为了效率把（猜），强制刷新读取instance_的值，防止进入第一个check去竞争那个锁，不加也是不会有错的，因为POSIX规定mutex之间必须保持内存的可见性，所以是不需要担心读到脏数据) &lt;-- 这段是个人意见，欢迎修正。<br /><br />下面就是我趴了半下午才想明白的问题。。。为啥Theron中那段代码（第一段代码）不需要在lock中添加mb()，后来往下翻了下，发现StringPool的构造函数是空的。。根本就没有内存的写入，当然就不需要wmb()了。<br /><br /><br />可见，C++的多线程编程，好难<br /><img src ="http://www.cppblog.com/pwq1989/aggbug/205228.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwq1989/" target="_blank">右席</a> 2014-01-08 00:54 <a href="http://www.cppblog.com/pwq1989/archive/2014/01/08/205228.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>