﻿<?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://www.cppblog.com/pwq1989/</link><description /><language>zh-cn</language><lastBuildDate>Thu, 23 Apr 2026 06:08:00 GMT</lastBuildDate><pubDate>Thu, 23 Apr 2026 06:08:00 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>1</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>systemtap + tengine lua 性能测试笔记</title><link>http://www.cppblog.com/pwq1989/archive/2015/01/09/209448.html</link><dc:creator>右席</dc:creator><author>右席</author><pubDate>Fri, 09 Jan 2015 04:03:00 GMT</pubDate><guid>http://www.cppblog.com/pwq1989/archive/2015/01/09/209448.html</guid><wfw:comment>http://www.cppblog.com/pwq1989/comments/209448.html</wfw:comment><comments>http://www.cppblog.com/pwq1989/archive/2015/01/09/209448.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/pwq1989/comments/commentRss/209448.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwq1989/services/trackbacks/209448.html</trackback:ping><description><![CDATA[<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;">虽然nginx+lua开发一些小的web服务简单快捷，但是由于种种原因，配套的工具比较缺乏，监控工具和性能检测工具等等。而且lua作为一种跑在虚拟机的脚本语言，虽然做的短小精悍，但是。。。功能和可调优的空间还是欠缺了点。</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;">前段时间使用春哥的<a href="https://github.com/openresty/nginx-systemtap-toolkit" style="box-sizing: border-box; color: #428bca; text-decoration: none; background: transparent;">systemtap脚本</a>对我的lua服务做了下性能测试，这里记录一下折腾的历程</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;"><a href="https://sourceware.org/systemtap/" style="box-sizing: border-box; color: #428bca; text-decoration: none; background: transparent;">systemtap</a>是一个性能检测和调试跟踪的工具，最开始是为了调试内核被做出来的，后来添加了用户态跟踪的功能。</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;">春哥的脚本要求systemtap2.2以上，公司测试服务器自带的systemtap脚本的版本那是1.6，远远不够，所以必须手动编译一个。下载systamtap的源码，然后./configuare + make就可以直接编了。最开始碰到的问题是公司el5系统的服务器的elfutil版本太低，得自己编译一个高版本的elfutil然后指定路径。。。。我怕麻烦，就把一个空的测试机器重装成el6，elfutil的版本立马就够了(我真是太机智了)。</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;">顺利编译出systamtap之后(中途遇到了systemtap版本不够新导致的符号找不到的bug)，就是tengine的安装，时间都折腾在这上面了。。。我们项目用的是tengine-ads这个版本，直接用tengine缺少模块，就请了tengine组的同学帮忙把模块给打了进去。由于要跟踪lua内部，所以自带的luajit必须-g编译。那边的同学比较忙，我就只能自己要了服务器权限跑上去自己编，编了几次之后那个测试服务器竟然磁盘满了。。。总之就是折腾了一晚上和一早上，终于把带debuginfo的tengine给装上了。</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;">启动tengine服务，把压测程序开好，运行</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=""  stylus"="" 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;">./ngx-sample-lua-bt -<span style="box-sizing: border-box;">p</span> <span style="box-sizing: border-box; color: #ae81ff;">29237</span> --luajit20 -t <span style="box-sizing: border-box; color: #ae81ff;">200</span> -<span style="box-sizing: border-box;">a</span> <span style="box-sizing: border-box; color: #e6db74;">'--vp 02 -R /home/wenqian.peiwq/systemtap-2.6/runtime -DSTP_NO_OVERLOAD --all-modules -DMAXSKIPPED=1024 '</span> &gt; tmp<span style="box-sizing: border-box;">.bt</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;">采样结束后，利用brendangregg的<a href="https://github.com/brendangregg/FlameGraph" style="box-sizing: border-box; color: #428bca; text-decoration: none; background: transparent;">FlameGraph tools</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;"><a href="http://img1.tbcdn.cn/L1/461/1/4ab524be3d4381a6697f23b8fc4474d5bf329f94" target="_blank" style="box-sizing: border-box; color: #428bca; text-decoration: none; background: transparent;"><img src="http://img1.tbcdn.cn/L1/461/1/4ab524be3d4381a6697f23b8fc4474d5bf329f94" alt="flamegraph" title="flamegraph" style="box-sizing: border-box; border: 0px; vertical-align: middle; max-width: 100%;" /></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;">通过这个图，先是立马发现了一个低级错误。。。（上面贴的图上已经没了），我有很多打印debug的语句，用了这类用法</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=""  stylus"="" 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;">_log.<span style="box-sizing: border-box; color: #f92672;"><span style="box-sizing: border-box; color: #a6e22e;">log</span><span style="box-sizing: border-box; color: #f8f8f2;">(<span style="box-sizing: border-box; color: #e6db74;">"debug"</span>, <span style="box-sizing: border-box; color: #e6db74;">"xxx"</span>, util.print_r(some_data)</span></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;">忘记了lua的求值策略，虽然debug下的这个语句在生产环境中不执行，但是由于求值策略，<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;">util.print_r(some_data)</code>仍然会先求值，导致了很大的性能损失，接近1/4。</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;">同时也发现了UUID的生成所占用的时间也过分的长了一些，然后重写了这个方法，使用了resty.string库中的random模块(直接调用了ngx_*的C函数)，然后利用systemtap对比了前后的时间，提升了360%多，可见还是很有效果的。</p>
<h4>注:</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;">这个项目是基于我上次手撸的小框架<a href="http://www.cppblog.com/pwq1989/archive/2014/12/22/209273.html" style="box-sizing: border-box; color: #428bca; text-decoration: none; background: transparent;">dodolu</a>，根据这次的测试结果，框架的封装对我的项目造成的性能损失在1%以下。</p><img src ="http://www.cppblog.com/pwq1989/aggbug/209448.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwq1989/" target="_blank">右席</a> 2015-01-09 12:03 <a href="http://www.cppblog.com/pwq1989/archive/2015/01/09/209448.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>自撸web小框架 dodolu(基于nginx lua) + lua debugger</title><link>http://www.cppblog.com/pwq1989/archive/2014/12/22/209273.html</link><dc:creator>右席</dc:creator><author>右席</author><pubDate>Mon, 22 Dec 2014 10:22:00 GMT</pubDate><guid>http://www.cppblog.com/pwq1989/archive/2014/12/22/209273.html</guid><wfw:comment>http://www.cppblog.com/pwq1989/comments/209273.html</wfw:comment><comments>http://www.cppblog.com/pwq1989/archive/2014/12/22/209273.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/pwq1989/comments/commentRss/209273.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwq1989/services/trackbacks/209273.html</trackback:ping><description><![CDATA[<h2>背景</h2>
<p>前段时间项目需要一个点击服务，大致是要根据用户请求的url及数据库中的规则，匹配出一个结果并记录日志。最开始是一个很小的需求，结果业务越来越复杂，业务逻辑中经常要处理header头和一些其他的信息，导致代码越来越混乱。在一期结束之后，抽时间把这段时间的工作抽象出了一个轻量级框架，只做了适量的封装，加入了代码生成的模块，可以帮助开发者迅速做出一个可用的web服务。</p>
<h2>介绍</h2>
<p>dodolu框架地址(<a href="https://github.com/pwq1989/dodolu">Github</a>)。</p>
<p>该框架只做了最小化的封装，几乎没有性能损失，并提供了根据配置文件(meta.lua)，自动生成route模块，nginx.conf配置，logger模块的功能，减轻了开发工作量，避免重复手写大量易错的配置或字符串变量，有助于多人开发统一风格。</p>
<blockquote>
<p>详情<a href="https://github.com/pwq1989/dodolu">Github</a>的README</p>
</blockquote>
<h2>功能</h2>
<p>包括三个部分，一个是<a href="https://github.com/pwq1989/dodolu/tree/master/ddl">web框架</a>，一个是<a href="https://github.com/pwq1989/dodolu/tree/master/tools">代码自动生成</a>模块，一个是魔改出的<a href="https://github.com/pwq1989/dodolu/tree/master/ddl/lualibs/debug">lua远程调试器</a>。</p>
<h3>web框架部分</h3>
<p>只有1k行以下的代码，集成了resty.template、resty.cookie、UUID生成等第三方模块。提供request、response、context、util等库方便开发人员使用。</p>
<h3>代码自动生成部分</h3>
<p>可自动生成:</p>
<ol>
     <li>路由配置</li>
     <li>日志记录模块</li>
     <li>nginx.conf</li>
</ol>
<p>主要目的在于解决nginx配置与lua代码的分离问题(在日志记录中尤为严重)。</p>
<p>开发人员新建应用步骤：在App文件夹下，新建lua文件，然后填入<code>do_get()</code>方法即可处理相应的get请求，所有配置在<code>meta/meta.lua</code>里面。</p>
<p>一个记录日志并返回1x1gif的例子：</p>
<pre><code data-language="">-- 这个文件下面存放你的业务逻辑<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 />
-->--&nbsp;这个文件下面存放你的业务逻辑<br />
local&nbsp;app&nbsp;=&nbsp;{}
function&nbsp;app.do_get(ctx)&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;response&nbsp;=&nbsp;ctx.response
&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;request&nbsp;=&nbsp;ctx.request
&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;cookie&nbsp;=&nbsp;ctx.cookie<br />
&nbsp;&nbsp;&nbsp;&nbsp;response:set_content_type("text/html")
&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;url&nbsp;=&nbsp;request.uri
&nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;<span style="color: #0000FF; ">do</span>&nbsp;some&nbsp;process<br />
&nbsp;&nbsp;&nbsp;&nbsp;-------------&nbsp;write&nbsp;log&nbsp;---------------
&nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;my_log&nbsp;日志模块是根据meta.lua自动生成的
&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;logger&nbsp;=&nbsp;ctx.get_logger('my_log')&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;log_data&nbsp;=&nbsp;{&nbsp;a&nbsp;=&nbsp;"xxx"}
&nbsp;&nbsp;&nbsp;&nbsp;logger.write(log_data,&nbsp;other_params<img src="http://www.cppblog.com/Images/dot.gif" alt="" />)<br />
&nbsp;&nbsp;&nbsp;&nbsp;-------------&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;empty&nbsp;gif&nbsp;-------
&nbsp;&nbsp;&nbsp; response:empty_gif()
&nbsp;&nbsp;&nbsp;&nbsp;response:close()
end<br />
function&nbsp;app.do_post(ctx)&nbsp;end
function&nbsp;app.do_put(ctx)&nbsp;end
function&nbsp;app.do_delete(ctx)&nbsp;end<br />
<span style="color: #0000FF; ">return</span>&nbsp;app</div>

</code></pre>
<h3>lua远程调试器</h3>
<p>文档详细见<a href="https://github.com/pwq1989/dodolu/tree/master/ddl/lualibs/debug">这里</a>，这里只演示下用法：<br />
<code>sh debug.sh</code>，然后运行用户程序，成功后<br />
<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 />
-->Lua&nbsp;Remote&nbsp;Debugger<br />
Run&nbsp;the&nbsp;program&nbsp;you&nbsp;wish&nbsp;to&nbsp;debug<br />
Paused&nbsp;at&nbsp;file&nbsp;a.lua<br />
Type&nbsp;'help'&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;commands<br />
&gt;&nbsp;</div>
<pre><br />
</pre>
<p>下一步 &nbsp;<code>n<br />
<br />
</code></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 />
-->n<br />
Paused&nbsp;at&nbsp;file&nbsp;a.lua&nbsp;line&nbsp;8<br />
8:&nbsp;print("Start")<br />
&gt;&nbsp;</div>
<p><br />
查看源码<font face="monospace">&nbsp; l<br />
<br />
</font></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 />
-->&gt;&nbsp;l&nbsp;&nbsp;<br />
source&nbsp;file:&nbsp;a.lua<br />
2:&nbsp;&nbsp;&nbsp;<br />
3:&nbsp;&nbsp;&nbsp;local&nbsp;tab&nbsp;=&nbsp;{<br />
4:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foo&nbsp;=&nbsp;1,<br />
5:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bar&nbsp;=&nbsp;2<br />
6:&nbsp;&nbsp;&nbsp;}<br />
7:&nbsp;&nbsp;&nbsp;<br />
8:&gt;&gt;&nbsp;print("Start")<br />
9:&nbsp;&nbsp;&nbsp;<br />
10:&nbsp;&nbsp;local&nbsp;bb&nbsp;=&nbsp;require&nbsp;"b"<br />
11:&nbsp;&nbsp;bb.foo()<br />
12:&nbsp;&nbsp;&nbsp;<br />
13:&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;i&nbsp;=&nbsp;1,&nbsp;10&nbsp;<span style="color: #0000FF; ">do</span><br />
14:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("Loop")</div>
<p><br />
</p>
<p>设置断点 &nbsp;&nbsp;<code>b &lt;file&gt;:&lt;line&gt;</code>&nbsp; &nbsp;查看 &nbsp; &nbsp;<code>listb<br />
<br />
</code></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 />
-->&gt;&nbsp;b&nbsp;a.lua:11<br />
&gt;&nbsp;listb&nbsp;<br />
a.lua:&nbsp;11</div>
<p>查看局部变量 &nbsp;<code>local</code></p><pre><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 />
-->&gt;&nbsp;local
{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;["tab"]&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;&nbsp;&nbsp;&nbsp;&nbsp;["bar"]&nbsp;=&nbsp;2,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;["foo"]&nbsp;=&nbsp;1,
&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;"table:&nbsp;0x2589ee0",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
}</div>
</pre>
<p>查看变量 &nbsp;&nbsp;<code>p tab<br />
<br />
</code></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 />
-->&gt;&nbsp;p&nbsp;tab<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;["bar"]&nbsp;=&nbsp;2,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;["foo"]&nbsp;=&nbsp;1,<br />
}</div>
<pre><span style="font-family: verdana, 'courier new';">继续执行，直到断点 &nbsp;</span><code>r</code></pre><pre><code data-language=""><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 />
-->&gt;&nbsp;r
Paused&nbsp;at&nbsp;file&nbsp;a.lua&nbsp;line&nbsp;11</div>

<br />
<br />
</code></pre><img src ="http://www.cppblog.com/pwq1989/aggbug/209273.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-12-22 18:22 <a href="http://www.cppblog.com/pwq1989/archive/2014/12/22/209273.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><item><title>（二）Luajit中的好轮子DynASM</title><link>http://www.cppblog.com/pwq1989/archive/2013/11/30/204508.html</link><dc:creator>右席</dc:creator><author>右席</author><pubDate>Sat, 30 Nov 2013 04:49:00 GMT</pubDate><guid>http://www.cppblog.com/pwq1989/archive/2013/11/30/204508.html</guid><wfw:comment>http://www.cppblog.com/pwq1989/comments/204508.html</wfw:comment><comments>http://www.cppblog.com/pwq1989/archive/2013/11/30/204508.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/pwq1989/comments/commentRss/204508.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwq1989/services/trackbacks/204508.html</trackback:ping><description><![CDATA[本人博客地址：<a href="http://www.cppblog.com/pwq1989/">http://www.cppblog.com/pwq1989/</a><br /><br />上一篇对Luajit的代码结构和编译过程做了简单的描述，这一篇就讲一下buildvm在第一步预处理dasc文件的过程和DynASM这个轮子。<br /><br />官方连接：<a href="http://luajit.org/dynasm.html">http://luajit.org/dynasm.html</a><br /><br />是为了让你更优雅的C里面撸汇编的一个工具，我记得以前看过一个老外的blog对比过同样功能的jit code generator的语法，Luajit的作者显然品位还是很高的。<br /><br />我们先来看看如果不用工具硬生生撸代码的话会发生什么。<br />1、你往一段内存里面写0xB8,0x00,0x01....<br />2、你在文件里定义好多label，写个copy section的宏往内存里面复制，你还不能确定里面到底是什么。（哦。。这个的术语叫Threaded。。。）<br /><br />然后再对比下<a href="https://code.google.com/p/asmjit/wiki/Examples" title="AsmJit" target="_blank">AsmJit</a>或者<a href="https://github.com/herumi/xbyak/blob/master/sample/bf.cpp" title="Xbyak" target="_blank">Xbyak</a>的例子看看（他们的功能差不多），DynASM还提供了.marco实现，就会发现语法真是sweeeet~<br /><br />这是我写着玩的一个草泥马语jit解释器（<a href="https://github.com/pwq1989/GMHjit">https://github.com/pwq1989/GMHjit</a>）语法真是清新自然啊，如果你想看工业级的应用，可以看看Google的Haberman写的protobuf的upb库，里面用DynASM进行了jit，号称快了多少多少（不去考证了），或者是agentzh写的sregex正则库，也是用它做了jit。一般来说DSL配上jit的话一定会快很多就错不了了。<br /><br />下面给一个DynASM的Demo程序（摘抄自<a href="http://blog.reverberate.org/2012/12/hello-jit-world-joy-of-simple-jits.html" title="这个blog">这个blog</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;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;DynASM&nbsp;directives.</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #008000; "></span>|.arch&nbsp;x64<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;|.actionlist&nbsp;actions<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;This&nbsp;define&nbsp;affects&nbsp;"|"&nbsp;DynASM&nbsp;lines.&nbsp;&nbsp;"Dst"&nbsp;must<br /></span><span style="color: #008080; ">&nbsp;6</span>&nbsp;<span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;resolve&nbsp;to&nbsp;a&nbsp;dasm_State**&nbsp;that&nbsp;points&nbsp;to&nbsp;a&nbsp;dasm_State*.</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;7</span>&nbsp;<span style="color: #008000; "></span><span style="color: #0000FF; ">#define</span>&nbsp;Dst&nbsp;&amp;state<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;main(<span style="color: #0000FF; ">int</span>&nbsp;argc,&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*argv[])&nbsp;{<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(argc&nbsp;&lt;&nbsp;2)&nbsp;{<br /><span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"Usage:&nbsp;jit1&nbsp;&lt;integer&gt;\n");<br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;1;<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">14</span>&nbsp;&nbsp;<br /><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;num&nbsp;=&nbsp;atoi(argv[1]);<br /><span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;dasm_State&nbsp;*state;<br /><span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;initjit(&amp;state,&nbsp;actions);<br /><span style="color: #008080; ">18</span>&nbsp;&nbsp;<br /><span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Generate&nbsp;the&nbsp;code.&nbsp;&nbsp;Each&nbsp;line&nbsp;appends&nbsp;to&nbsp;a&nbsp;buffer&nbsp;in<br /></span><span style="color: #008080; ">20</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;"state",&nbsp;but&nbsp;the&nbsp;code&nbsp;in&nbsp;this&nbsp;buffer&nbsp;is&nbsp;not&nbsp;fully&nbsp;linked<br /></span><span style="color: #008080; ">21</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;yet&nbsp;because&nbsp;labels&nbsp;can&nbsp;be&nbsp;referenced&nbsp;before&nbsp;they&nbsp;are<br /></span><span style="color: #008080; ">22</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;defined.<br /></span><span style="color: #008080; ">23</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">24</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;The&nbsp;run-time&nbsp;value&nbsp;of&nbsp;C&nbsp;variable&nbsp;"num"&nbsp;is&nbsp;substituted<br /></span><span style="color: #008080; ">25</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;into&nbsp;the&nbsp;immediate&nbsp;value&nbsp;of&nbsp;the&nbsp;instruction.</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">26</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;|&nbsp;&nbsp;mov&nbsp;eax,&nbsp;num<br /><span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;ret<br /><span style="color: #008080; ">28</span>&nbsp;&nbsp;<br /><span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Link&nbsp;the&nbsp;code&nbsp;and&nbsp;write&nbsp;it&nbsp;to&nbsp;executable&nbsp;memory.</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">30</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;(*fptr)()&nbsp;=&nbsp;jitcode(&amp;state);<br /><span style="color: #008080; ">31</span>&nbsp;&nbsp;<br /><span style="color: #008080; ">32</span>&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Call&nbsp;the&nbsp;JIT-ted&nbsp;function.</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">33</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;ret&nbsp;=&nbsp;fptr();<br /><span style="color: #008080; ">34</span>&nbsp;&nbsp;&nbsp;assert(num&nbsp;==&nbsp;ret);<br /><span style="color: #008080; ">35</span>&nbsp;&nbsp;<br /><span style="color: #008080; ">36</span>&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Free&nbsp;the&nbsp;machine&nbsp;code.</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">37</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;free_jitcode(fptr);<br /><span style="color: #008080; ">38</span>&nbsp;&nbsp;<br /><span style="color: #008080; ">39</span>&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;ret;<br /><span style="color: #008080; ">40</span>&nbsp;}</div><br />预处理之后那就会变成这样子：<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;<span style="color: #008000; ">//</span><span style="color: #008000; ">|.arch&nbsp;x64<br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">|.actionlist&nbsp;actions</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #008000; "></span><span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">const</span>&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;actions[4]&nbsp;=&nbsp;{<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;184,237,195,255<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;};<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;[<img src="http://www.cppblog.com/Images/dot.gif" alt="" />]<br /></span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #008000; ">&nbsp;<br /></span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">|&nbsp;&nbsp;mov&nbsp;eax,&nbsp;num<br /></span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">|&nbsp;&nbsp;ret</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #008000; "></span>dasm_put(Dst,&nbsp;0,&nbsp;num);</div>dasm_put就是把num参数和actions[]一起放入了Dst（#define Dst &amp;state）的制定的内存中，这时候已经是机器码的形式了。<br />下面是对于acitons[]数组内容的解释：<br />184(B8)-- mov eax, [immediate] 指令的第一个字节<br />237 &nbsp; &nbsp; &nbsp; -- 内置的标志DASM_IMM_D, 指明应该放入一个4字节宽度的参数，与上一条指令完成一个MOV<br />195(C3)-- 对应ret指令<br />255 &nbsp; &nbsp; &nbsp; --&nbsp;内置的标志DASM_STOP<br /><br />以上就是最简单的例子，dasm_growpc()是内置的函数，用来增长maxpc, 这样在程序里面就可以方便写出jmp =&gt; label 这样的指令了。<br /><br />由于DynASM的文档很少，幸亏还有几个例子，除了例子唯一能看的就是源码了，所以在用的时候出现问题是很痛苦的。。当时写GMHjit就发现了蛋疼的pre-process period bug，后来绕过去了。<br /><br />源码文件有这么几个<br />-- dynasm.lua<br />-- dynasm_proto.h<br />-- dynasm_*.lua<br />-- dynasm_*.h &nbsp;// * x64 &nbsp;x86 &nbsp;ppc mips arm 等target<br /><br />用起来就是lua dynasm.lua a.dasm &gt; a.h&nbsp;<br /><br />下面就从dynasm.lua开始分析下他的源码<br /><br />入口是parseargs函数，里面给的g_opt参数赋默认的值，一个repeat 中调用parseopt解析参数，opt_map就是option对args的函数映射。<br /><br />函数wline，wcomment，wsync，wdumplines都是对输出的目标文件的操作。<br /><br />真正的主函数是 translate，把input file变成 output file，在readfile中的doline函数是真正的处理过程，里面判断是否是Assembler line之后Emit C code，调用dostmt(aline)。里面继续有map_coreop[*]来处理section macro arch nop_ error_1 include &nbsp;if endif elseif 等关键字，想深入研究的可以自己去看，其中在loadarch中根据arch加载不同的lua库<br /><br />如果arch是x64的话，本质还是require x86<br />来看dasm_x86.lua文件<br /><br /><div>_M.mergemaps这是关键的方法，设置了2个Map的元方法，然后返回，相当于是把方法绑定在table里面传递了出去。处理后文件中关键的actionlist[]数组和Dasm_put(Dst, ...)的输出就是这个lua文件的方法。</div>里面提供了很多dump方法，可以供我们遇到问题时候调试处理过程。<br /><br /><div>action_names就是以后生成的action_list中的内置标志定义，必须与dasm_x86.h中的enum定义一致。</div>表明了代表的参数和长度等信息。<br />这个文件里面所有的函数就是做了一件事，把你的 |... &nbsp;这样子的代码处理成数组输出到目标文件中（我是汇编渣渣，里面貌似支持SSE2、3、4+，看不懂，等到以后看到traced jit的时候再去翻手册把）<br /><br />预处理完成之后，就是#include "dasm_x86.h"，里面有最关键的dasm_State结构体的定义，几乎里面所有的函数都是对外的API，有init,setup,free等等，除去初始化与free之外，有三个步骤是需要出现在你都代码中：<br />1、dasm_put(Dst,...) 这个是自动生成的，不用我们操心，根据actionlist[]和运行时的参数写入到Dst指定的内存（Dst-&gt;section）中.<br />2、dasm_link() 第二个参数是返回的代码长度大小，这个函数把section合并到一起，处理偏移等等。<br />3、dasm_encode() 第二个参数是一个接受encode输出的buffer指针。<br /><br />然后就可以用一个函数指针，比如声明一个 int (*f)(*int), int ret = f(param) 直接运行刚刚生成的机器码了。<br /><br /><br /><br /><br /><br /><a href="http://luajit.org/dynasm.html"><br /></a><img src ="http://www.cppblog.com/pwq1989/aggbug/204508.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwq1989/" target="_blank">右席</a> 2013-11-30 12:49 <a href="http://www.cppblog.com/pwq1989/archive/2013/11/30/204508.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（一）初识Luajit</title><link>http://www.cppblog.com/pwq1989/archive/2013/11/28/204487.html</link><dc:creator>右席</dc:creator><author>右席</author><pubDate>Thu, 28 Nov 2013 11:23:00 GMT</pubDate><guid>http://www.cppblog.com/pwq1989/archive/2013/11/28/204487.html</guid><wfw:comment>http://www.cppblog.com/pwq1989/comments/204487.html</wfw:comment><comments>http://www.cppblog.com/pwq1989/archive/2013/11/28/204487.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/pwq1989/comments/commentRss/204487.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/pwq1989/services/trackbacks/204487.html</trackback:ping><description><![CDATA[本人博客地址：<a href="http://www.cppblog.com/pwq1989/">http://www.cppblog.com/pwq1989/</a><br /><br />第一篇对Luajit做一个大概的介绍，我目前也正在慢慢的读通源码中，以后发现了新东西就补充在这里。<br />
<br />
大家可以从官网下载到源码（<a href="http://luajit.org/">http://luajit.org/</a>），也可以从Github（<a href="https://github.com/LuaDist/luajit">https://github.com/LuaDist/luajit</a>）down下来，顺便还可以看下commit记录。<br />
<br />
大家对着luajit的wiki结合源码看的话会更好些，因为。。文档太特么少了！！<br />
<br />
目录结构：<br />
-- src<br />
&nbsp; &nbsp; -- host<br />
&nbsp; &nbsp; -- jit<br />
&nbsp; &nbsp; *.c<br />
&nbsp; &nbsp; *.h<br />
&nbsp; &nbsp; *.dasc<br />
等等，别的不是很重要<br />
<br />
最开始我是从main函数开始看的，然后。。碰了一鼻子灰，后来研究下他的makefile，发现他是这样子的编译的，贴一下关键的msvcbuild.bat的代码（这个更容易看懂）<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 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;:X64<br />
<span style="color: #008080; ">&nbsp;2</span>&nbsp;minilua&nbsp;%DASM%&nbsp;-LN&nbsp;%DASMFLAGS%&nbsp;-o&nbsp;host\buildvm_arch.h&nbsp;vm_x86.dasc<br />
<span style="color: #008080; ">&nbsp;3</span>&nbsp;@if&nbsp;errorlevel&nbsp;1&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;:BAD<br />
<span style="color: #008080; ">&nbsp;4</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;5</span>&nbsp;%LJCOMPILE%&nbsp;/I&nbsp;"."&nbsp;/I&nbsp;%DASMDIR%&nbsp;host\buildvm*.c<br />
<span style="color: #008080; ">&nbsp;6</span>&nbsp;@if&nbsp;errorlevel&nbsp;1&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;:BAD<br />
<span style="color: #008080; ">&nbsp;7</span>&nbsp;%LJLINK%&nbsp;/<span style="color: #0000FF; ">out</span>:buildvm.exe&nbsp;buildvm*.obj<br />
<span style="color: #008080; ">&nbsp;8</span>&nbsp;@if&nbsp;errorlevel&nbsp;1&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;:BAD<br />
<span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;exist&nbsp;buildvm.exe.manifest^<br />
<span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;%LJMT%&nbsp;-manifest&nbsp;buildvm.exe.manifest&nbsp;-outputresource:buildvm.exe<br />
<span style="color: #008080; ">11</span>&nbsp;<br />
<span style="color: #008080; ">12</span>&nbsp;buildvm&nbsp;-m&nbsp;peobj&nbsp;-o&nbsp;lj_vm.obj<br />
<span style="color: #008080; ">13</span>&nbsp;@if&nbsp;errorlevel&nbsp;1&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;:BAD<br />
<span style="color: #008080; ">14</span>&nbsp;buildvm&nbsp;-m&nbsp;bcdef&nbsp;-o&nbsp;lj_bcdef.h&nbsp;%ALL_LIB%<br />
<span style="color: #008080; ">15</span>&nbsp;@if&nbsp;errorlevel&nbsp;1&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;:BAD<br />
<span style="color: #008080; ">16</span>&nbsp;buildvm&nbsp;-m&nbsp;ffdef&nbsp;-o&nbsp;lj_ffdef.h&nbsp;%ALL_LIB%<br />
<span style="color: #008080; ">17</span>&nbsp;@if&nbsp;errorlevel&nbsp;1&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;:BAD<br />
<span style="color: #008080; ">18</span>&nbsp;buildvm&nbsp;-m&nbsp;libdef&nbsp;-o&nbsp;lj_libdef.h&nbsp;%ALL_LIB%<br />
<span style="color: #008080; ">19</span>&nbsp;@if&nbsp;errorlevel&nbsp;1&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;:BAD<br />
<span style="color: #008080; ">20</span>&nbsp;buildvm&nbsp;-m&nbsp;recdef&nbsp;-o&nbsp;lj_recdef.h&nbsp;%ALL_LIB%<br />
<span style="color: #008080; ">21</span>&nbsp;@if&nbsp;errorlevel&nbsp;1&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;:BAD<br />
<span style="color: #008080; ">22</span>&nbsp;buildvm&nbsp;-m&nbsp;vmdef&nbsp;-o&nbsp;jit\vmdef.lua&nbsp;%ALL_LIB%<br />
<span style="color: #008080; ">23</span>&nbsp;@if&nbsp;errorlevel&nbsp;1&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;:BAD<br />
<span style="color: #008080; ">24</span>&nbsp;buildvm&nbsp;-m&nbsp;folddef&nbsp;-o&nbsp;lj_folddef.h&nbsp;lj_opt_fold.c<br />
<span style="color: #008080; ">25</span>&nbsp;@if&nbsp;errorlevel&nbsp;1&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;:BAD</div>
<br />
先创建了一个buildvm.exe的中间工具，来自动生成代码，分别生成了<span style="font-size: 13.333333015441895px; background-color: #eeeeee;">lj_vm.obj，</span><span style="font-size: 13.333333015441895px; background-color: #eeeeee;">lj_bcdef.h，</span><span style="font-size: 13.333333015441895px; background-color: #eeeeee;">lj_ffdef.h ，</span><span style="font-size: 13.333333015441895px; background-color: #eeeeee;">lj_recdef.h ，</span><span style="font-size: 13.333333015441895px; background-color: #eeeeee;">jit\vmdef.lua，</span><span style="font-size: 13.333333015441895px; background-color: #eeeeee;">lj_folddef.h， lj_libdef.h<br />
<br />
</span>其中lv_vm.obj是依赖于<span style="font-size: 13.333333015441895px; background-color: #eeeeee;">host\buildvm_arch.h</span>的，这个是用DynASM预处理vm_x86.dasc生成的，这个工具的具体分析会在下一篇博客提及。<br />
<br />
先来看下上面自动生成的代码：<br />
lj_bcdef.h:<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;LJ_DATADEF&nbsp;<span style="color: #0000FF; ">const</span>&nbsp;uint16_t&nbsp;lj_bc_ofs[]&nbsp;=&nbsp;{<br />
<span style="color: #008080; ">&nbsp;2</span>&nbsp;0,<br />
<span style="color: #008080; ">&nbsp;3</span>&nbsp;71,<br />
<span style="color: #008080; ">&nbsp;4</span>&nbsp;142,<br />
<span style="color: #008080; ">&nbsp;5</span>&nbsp;213,<br />
<span style="color: #008080; ">&nbsp;6</span>&nbsp;284,<br />
<span style="color: #008080; ">&nbsp;7</span>&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br />
<span style="color: #008080; ">&nbsp;8</span>&nbsp;};<br />
<span style="color: #008080; ">&nbsp;9</span>&nbsp;<br />
<span style="color: #008080; ">10</span>&nbsp;LJ_DATADEF&nbsp;<span style="color: #0000FF; ">const</span>&nbsp;uint16_t&nbsp;lj_bc_mode[]&nbsp;=&nbsp;{<br />
<span style="color: #008080; ">11</span>&nbsp;BCDEF(BCMODE)<br />
<span style="color: #008080; ">12</span>&nbsp;BCMODE_FF,<br />
<span style="color: #008080; ">13</span>&nbsp;BCMODE_FF,<br />
<span style="color: #008080; ">14</span>&nbsp;BCMODE_FF,<br />
<span style="color: #008080; ">15</span>&nbsp;BCMODE_FF,<br />
<span style="color: #008080; ">16</span>&nbsp;BCMODE_FF,<br />
<span style="color: #008080; ">17</span>&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br />
<span style="color: #008080; ">18</span>&nbsp;};</div>
<br />lj_bc_ofs[]可能是bc在vm代码段中的偏移量（这个我还没深入进去调试一下），vm的一部分是用DynASM直接撸汇编撸出来的，wiki中也有提到下一步jit化的opcode等等。<br /><div>lj_bc_mode[]的用来根据压缩后的bytecode构造，分离出操作数，第一行的两个宏的定义是<br /><div>#define BCMODE(name, ma, mb, mc, mm) \</div><div>&nbsp; (BCM##ma|(BCM##mb&lt;&lt;3)|(BCM##mc&lt;&lt;7)|(MM_##mm&lt;&lt;11)),</div><div>#define BCMODE_FF<span style="white-space:pre">	</span>0<br /><br /><div>#define BCDEF(_) \</div><div>&nbsp; /* Comparison ops. ORDER OPR. */ \</div><div>&nbsp; _(ISLT,<span style="white-space:pre">	</span>var,<span style="white-space:pre">	</span>___,<span style="white-space:pre">	</span>var,<span style="white-space:pre">	</span>lt) \</div><div>&nbsp; _(ISGE,<span style="white-space:pre">	</span>var,<span style="white-space:pre">	</span>___,<span style="white-space:pre">	</span>var,<span style="white-space:pre">	</span>lt) \</div><div>&nbsp; _(ISLE,<span style="white-space:pre">	</span>var,<span style="white-space:pre">	</span>___,<span style="white-space:pre">	</span>var,<span style="white-space:pre">	</span>le) \</div><div>&nbsp; _(ISGT,<span style="white-space:pre">	</span>var,<span style="white-space:pre">	</span>___,<span style="white-space:pre">	</span>var,<span style="white-space:pre">	</span>le) \<br />...<br />总之就是充斥着各种拼接起来的宏<br /><br />lj_ffdef.h:<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;FFDEF(assert)<br /><span style="color: #008080; ">2</span>&nbsp;FFDEF(type)<br /><span style="color: #008080; ">3</span>&nbsp;FFDEF(next)<br /><span style="color: #008080; ">4</span>&nbsp;FFDEF(pairs)<br /><span style="color: #008080; ">5</span>&nbsp;FFDEF(ipairs_aux)<br /><span style="color: #008080; ">6</span>&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /></div>FFDEF的定义是在<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;<span style="color: #008000; ">/*</span><span style="color: #008000; ">&nbsp;Fast&nbsp;function&nbsp;ID.&nbsp;</span><span style="color: #008000; ">*/</span><br /><span style="color: #008080; ">2</span>&nbsp;typedef&nbsp;<span style="color: #0000FF; ">enum</span>&nbsp;{<br /><span style="color: #008080; ">3</span>&nbsp;&nbsp;&nbsp;FF_LUA_&nbsp;=&nbsp;FF_LUA,&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">/*</span><span style="color: #008000; ">&nbsp;Lua&nbsp;function&nbsp;(must&nbsp;be&nbsp;0).&nbsp;</span><span style="color: #008000; ">*/</span><br /><span style="color: #008080; ">4</span>&nbsp;&nbsp;&nbsp;FF_C_&nbsp;=&nbsp;FF_C,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">/*</span><span style="color: #008000; ">&nbsp;Regular&nbsp;C&nbsp;function&nbsp;(must&nbsp;be&nbsp;1).&nbsp;</span><span style="color: #008000; ">*/</span><br /><span style="color: #008080; ">5</span>&nbsp;<span style="color: #0000FF; ">#define</span>&nbsp;FFDEF(name)&nbsp;&nbsp;&nbsp;&nbsp;FF_##name,<br /><span style="color: #008080; ">6</span>&nbsp;#include&nbsp;"lj_ffdef.h"<br /><span style="color: #008080; ">7</span>&nbsp;&nbsp;&nbsp;FF__MAX<br /><span style="color: #008080; ">8</span>&nbsp;}&nbsp;FastFunc;</div>差不多就是用FF_##name把上面的名字拼接起来，然后生成在enum里面，这样就能当成是数字，在数组中迅速找到入口了<br /><br />vmdef.lua:<br />这个里面内容就不贴了，包括bcname,irname,irfpm,irfield,ircall 的定义，在jit文件夹下面，用于调试等，比如在dump.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 />-->local&nbsp;jit&nbsp;=&nbsp;require("jit")<br />assert(jit.version_num&nbsp;==&nbsp;20002,&nbsp;"LuaJIT&nbsp;core/library&nbsp;version&nbsp;mismatch")<br />local&nbsp;jutil&nbsp;=&nbsp;require("jit.util")<br />local&nbsp;vmdef&nbsp;=&nbsp;require("jit.vmdef") &nbsp;// &#8592;&nbsp;&#8592;&nbsp;&#8592;&nbsp;&#8592;</div><br />当你用luajit -jdump的时候，就是调用的lua的jit库里面的lua函数<br /><br />lj_recdef.h:<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;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">const</span>&nbsp;uint16_t&nbsp;recff_idmap[]&nbsp;=&nbsp;{<br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;0,<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;0x0100,<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;0x0200,<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;0x0300,<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;0,<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;0,<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;0x0400,<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br /><span style="color: #008080; ">10</span>&nbsp;};<br /><span style="color: #008080; ">11</span>&nbsp;<br /><span style="color: #008080; ">12</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">const</span>&nbsp;RecordFunc&nbsp;recff_func[]&nbsp;=&nbsp;{<br /><span style="color: #008080; ">13</span>&nbsp;recff_nyi,<br /><span style="color: #008080; ">14</span>&nbsp;recff_c,<br /><span style="color: #008080; ">15</span>&nbsp;recff_assert,<br /><span style="color: #008080; ">16</span>&nbsp;recff_type,<br /><span style="color: #008080; ">17</span>&nbsp;recff_ipairs_aux,<br /><span style="color: #008080; ">18</span>&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br /><span style="color: #008080; ">19</span>&nbsp;};</div>其中recff_func[]是被注册的被traced jit 跟踪的函数，具体可是在lj_ffrecord.c里面看到<br />recff_idmap[]被用在lj_ffrecord_func这个函数中，有一个关键的数据结构RecordFFData，用来记录在trace过程中被调用函数的参数和返回值个数，和一些辅助数据，opcode，literal等等。通过recff_idmap[]保存的值来区分函数（待仔细研究）<br /><br /><br />lj_folddef.h:<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;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">const</span>&nbsp;FoldFunc&nbsp;fold_func[]&nbsp;=&nbsp;{<br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;&nbsp;&nbsp;fold_kfold_numarith,<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;fold_kfold_ldexp,<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;fold_kfold_fpmath,<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;fold_kfold_numpow,<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;};<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">const</span>&nbsp;uint32_t&nbsp;fold_hash[916]&nbsp;=&nbsp;{<br /><span style="color: #008080; ">10</span>&nbsp;0xffffffff,<br /><span style="color: #008080; ">11</span>&nbsp;0xffffffff,<br /><span style="color: #008080; ">12</span>&nbsp;0x5b4c8016,<br /><span style="color: #008080; ">13</span>&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br /><span style="color: #008080; ">14</span>&nbsp;};</div>用在FOLD optimization中，见lj_opt_fold.c，主要在<br /><div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 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;<span style="color: #0000FF; ">if</span>&nbsp;((fh&nbsp;&amp;&nbsp;0xffffff)&nbsp;==&nbsp;k&nbsp;||&nbsp;(fh&nbsp;=&nbsp;fold_hash[h+1],&nbsp;(fh&nbsp;&amp;&nbsp;0xffffff)&nbsp;==&nbsp;k))&nbsp;{<br /><span style="color: #008080; ">2</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">ref</span>&nbsp;=&nbsp;(IRRef)tref_ref(fold_func[fh&nbsp;&gt;&gt;&nbsp;24](J));<br /><span style="color: #008080; ">3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(<span style="color: #0000FF; ">ref</span>&nbsp;!=&nbsp;NEXTFOLD)<br /><span style="color: #008080; ">4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">break</span>;<br /><span style="color: #008080; ">5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div>是根据数组偏移获取函数，直接执行。<br />（这个Optimation略复杂，以后的博文中再说）<br /><br />----------------------------------------分割线-------------------------------------------<br /><br />以上就是buildvm生成代码，在很多.c的文件中，他加入了一些无意义的MARCO，目的是为了能被buildvm识别出<br /><br />下面说说src根目录下面的文件：<br /><br />lauxlib.h：<br />用户开发扩展和与C交互的时候的头文件<br /><br />lib_*.h /.c:<br />顾名思义，就是利用LuaAPI写的内部标准库，会在方法上表明是否会被trace ( LJLIB_REC(.) )。<br /><br />ljamalg.c:<br />文件的合并<br /><br />lj_alloc.h /.c:<br />定制的Memory Allocator<br /><br />lj_api.c:<br /><div>Public Lua/C API.</div><br />lj_arch.h:<br /><div>Target architecture selection<br /><br />lj_jit.h:<br />jit编译器里面数据结构的定义</div><br />lj_asm.h/ .c &nbsp;lj_asm_*.c lj_emit_*.h lj_target_*.h/.c :<br />将IR编译成Machine Code，关键的数据结构ASMState，线性扫描的O(n2)分配算法<br /><br />lj_bc.h/ .c：<br />Luajit字节码的定义和内存布局<br /><br />lj_bcdump.c lj_bcread.c &nbsp;lj_bcwrite.c:<br />围绕着字节码的操作<br /><br />lj_carith.c:<br /><div>C实现的一些数字运算</div><br />lj_ccall.h/ .c &nbsp;lj_ccallback.h / .c :<br />FFI C语言函数调用和回调绑定<br /><br />lj_debug.h/.c :<br />调试与自省用<br /><br />lj_def.h:<br />这个很重要，重要的类型和一些宏定义在这里<br /><br />lj_c*.h/ .c:<br />和C语言先关的，比如类型转化，char管理，数据管理<br /><br />lj_frame.h:<br />Luajit的栈帧管理<br /><br />lj_func.h/.c:<br />Function handle和闭包有关的upvalue数据结构<br /><br />lj_gc.h/.c:<br />GC相关，GC可以看下luajit的wiki，里面涉及不少增量式GC的paper和作者的看法<br /><br />lj_gdbjit.h/.c :<br />对gdb的支持<br /><br />lj_ir*.h/.c:<br />SSA，IR相关（这个和bytecode还是不一样的）操作和优化<br /><br />lj_lex.h/.c &nbsp;lj_parse.h/.c:<br />lexer和parser<br /><br />lj_mcode.h/.c:<br />Machine Code管理<br /><br />lj_opt_*.h:<br />各种bytecode层面上的优化<br /><br />lj_snap.h/.c:<br />快照支持<br /><br />lj_state.h/.c:<br />LuaState和Stack的操作<br /><br />lj_str*.h/.c &nbsp;lj_tab.h/.c:<br />原生类型string和table操作<br /><br />lj_udata.h/.c:<br />类型user data的操作<br /><br />lj_vm.h/.c &nbsp;lj_vmevent.h/.c:<br />vm的API和事件注册（lj_vmevent_send）<br /><br />lj_vmmath.h/.c：<br />对vm支持的math库<br /><br />lua.h:<br />luaState等基本的Lua结构<br /><br />lualib.h:<br />和Lua一样，标准库的API<br /><br />luajit.h:<br />luajit 的public API<br /><br />vm_*.dasc:<br />编译期被DynASM预处理的源文件，下一篇讲DynASM时候介绍dasc文件<br /><br />wmain.c:<br />windows下面的main入口<br /><br />和Trace相关的：<br />lj_crecord.h/.c &nbsp;： C操作的trace record<br />lj_dispatch.h/.c : &nbsp;指令分发，调用ASMFuction，处理指令前的hook和记录trace用的hot count，有一个重要的数据结构 GG_State<br />lj_ff*.h/.c: 上面讲lj_ffdef.h的时候提过，trace的时候 记录Fast Function的调用记数<br />lj_trace.h/.c: trace的具体过程<br />lj_traceerr.h : trace error</div></div></div><img src ="http://www.cppblog.com/pwq1989/aggbug/204487.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/pwq1989/" target="_blank">右席</a> 2013-11-28 19:23 <a href="http://www.cppblog.com/pwq1989/archive/2013/11/28/204487.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>