<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Yanze Li (李彦泽)</title>
    <link>https://funemy.github.io/</link>
    
    <image>
      <url>https://funemy.github.io/favicon.ico</url>
      <title>Yanze Li (李彦泽)</title>
      <link>https://funemy.github.io/</link>
    </image>
    
    <atom:link href="https://funemy.github.io/rss2.xml" rel="self" type="application/rss+xml"/>
    
    <description>I disagree with everything I said.</description>
    <pubDate>Tue, 16 Dec 2025 05:40:32 GMT</pubDate>
    <generator>http://hexo.io/</generator>
    
    <item>
      <title>2020总结</title>
      <link>https://funemy.github.io/2020/12/28/2020-12-28-annual-review/</link>
      <guid>https://funemy.github.io/2020/12/28/2020-12-28-annual-review/</guid>
      <pubDate>Mon, 28 Dec 2020 23:28:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;p&gt;鉴于最近看到了好几篇优秀的年度总结，也想着总结一下自己的2020，顺便分享一下这一年不寻常的经历。实在太久没有用中文写点什么了，以至于我写到此处已经修改了无数错别字。要是有缘人看到这篇博客就当图一乐吧。&lt;/p&gt;
&lt;p&gt;因为一时也想不到什么很好的写作顺序，就大致按着自己脑中的</description>
          
        
      
      
      
      <content:encoded><![CDATA[<p>鉴于最近看到了好几篇优秀的年度总结，也想着总结一下自己的2020，顺便分享一下这一年不寻常的经历。实在太久没有用中文写点什么了，以至于我写到此处已经修改了无数错别字。要是有缘人看到这篇博客就当图一乐吧。</p><p>因为一时也想不到什么很好的写作顺序，就大致按着自己脑中的关键词和时间线来回忆吧。</p><h2 id="科比去世"><a class="markdownIt-Anchor" href="#科比去世"></a> 科比去世</h2><p>没错，这个居然是脑海里第一个跳出来的关键词，惭愧。</p><p>其实我已经好久没看球了，我也向来算不上什么体育运动爱好者。喜欢打篮球的原因大抵是初中高中实在太无聊，需要一些不会被老师家人反对的兴趣爱好来释放压力。</p><p>但篮球也确实给我那些年带来了无数欢乐。还记得高中我还叫嚣着幻想湖人继续夺冠，一喊就是三年，连我们班不看球的人都知道有我这号脑残粉天天在那叫嚣（笑）。</p><p>然而今年科比去世了，湖人夺冠了，我早不看球了，一晃10年了。很是唏嘘。</p><p>前短时间还看到朋友圈有好友分享安东尼回掘金的新闻，甚至回想起初中那会每天放学在公交车上用同学的手机靠2G网看腾讯体育新闻的日子，很是怀念。</p><p>我觉得我爱科比的原因非常简单，fancy。我觉得直到今天我依然对很多fancy但不那么实用的东西有莫名的好感（such as PL research，笑）。</p><p>科比的去世真的带走了心里很多的回忆。年初刚发生这件事的时候我还被一些同事笑话，毕竟和今年其他事比起来这好像实在上不了台面。</p><p>来美国前我就想着要在美国实现的三个小心愿：</p><ol><li>看一场科比的球</li><li>听一场Linkin Park的演唱会</li><li>听一场Green Day的演唱会</li></ol><p>这些都是我最真实的青春。然而我来的前一年科比退役了，我来美国之前Chester自杀了。好像我什么都慢了一步。希望自己还能有希望再朋克一把吧（笑）。</p><p>另外一个让我难过的是竹内结子的去世。本来想单独分一个section来几年一下我迷恋日剧多年最喜欢的女神。不过想来想去想说的话也大抵相同。有些生命就这样突然消逝了，伴随着一些很美好的记忆也就这样在脑海中埋藏起来，我还是要好好活下去。</p><h2 id="master毕业"><a class="markdownIt-Anchor" href="#master毕业"></a> Master毕业</h2><p>这大概可以算我可以骄傲一下的事。来A&amp;M的三年我大概一直在纠结要不要在导师手下直接拿PhD，感谢一些不愉快的事情让我看清楚了老板的本质，也下定决心要离开。</p><p>做决定的时候大概是2月，然后一直疲于工作到4月中旬，花了一个月左右从零把论文答辩都搞定了。那段时间人真的非常不好，每天都是焦虑到睡不着和对未来的纠结。</p><p>有一种自己很久的努力都喂狗了的气愤。好在结果是好的，我毕业了，老板在短暂的生气过后也没有为难我。我自觉得做了一个不错的答辩，也通过写论文好好捋了捋这3年做过的事，并从中找到了一些自己的价值。</p><p>很惭愧自己和那些真正的PL大佬比太弱了,我所做的科研在我看来都没有入PL的门。曾经一度打开推特看到一堆看不懂的讨论就无限自闭。</p><p>不过焦虑是没有用的，尤其在和Master了断了以后我也想的很开了。不论做什么事，时间的鸿沟是最难跨过的，与其焦虑，期待有捷径可走，不如就按照自己的节奏把时间花在自己感兴趣的事上。正视自己的弱，但不要过分贬低自己的工作，才是正确的态度。</p><p>我大概还是会走的慢一点，毕竟我是一个花了3年才毕业Master。不过不妨碍我更加自信地在这条路上走下去。</p><h2 id="科研"><a class="markdownIt-Anchor" href="#科研"></a> 科研</h2><p>其实这一年做过的科研可以说trival。毕竟我毕业以后老板直接把我从一些GitHub repo里移除了（笑）。</p><p>但最让我骄傲的是我们的SC paper被接受了。这大概是我3年在组里唯一觉得solid的工作，毕竟是自己从零写出来的，从代码到实验到论文，和Brad不知道熬了多少个夜。终于觉得自己做出了一点微小的贡献。</p><p>此外很感谢今年的ICFP mentoring program。让我在毕业以后还有项目可做，还认识了一些很nice的同事和教授。</p><p>然后自己莫名其妙的还混到了operations committe。我也不知道自己当时怎么想的，希望能帮到更多和我一样被折磨过的年轻人吧。</p><p>虽然我知道这是废话，但通过mentoring program，我也亲自确认了一件事：这个世界上就是有热爱科研和编程，并且为人师表的教授的。</p><p>我希望能变成这样的人，并且不希望变成我前老板那样的人，period。</p><h2 id="工作创业"><a class="markdownIt-Anchor" href="#工作创业"></a> 工作（创业？）</h2><p>我是真的不想多提起这段经历，这就是我过去两年的痛苦源泉。</p><p>你付出了200%的努力，然后被人当成廉价劳动力和工具随便使唤。你做出了真实的贡献，被人当成你欠他的债。</p><p>千言万语汇成一句话，慎重和老板创业。</p><p>顺便也回想起了本科愉快的创业经历。让我意识到做一个优秀的tech leader真的太需要在技术力之外的品质了。</p><p>一个聪明的混蛋是不可能成功的。虽然这可能在电影里很酷，但真的不要高估自己的智商，也不要把他人对你的善意当成理所当然。</p><p>同时让我认识到的是科研这座孤岛。一个优秀的研究者，尤其是当上faculty之后，是很难有渠道摄入批评的。</p><p>在系里，大多教授都是和你不同方向的，难以评价你的工作，平时低头不见抬头见，也没有人会做这种吃力不讨好的事。</p><p>你的学生可能忌惮于你的权利而不敢批评，或者你干脆就把学生的话当成耳旁风。</p><p>在领域里，大家都利益相关，又很少能知道group内部的真实情况，所以聊天大多是互相吹捧。</p><p>由此，一个科研工作者很可能陷入自我膨胀中，而不能客观审视自己成果的局限性。</p><p>我不知道怎么去改变这些问题，但我觉得人不能，至少不应该去否定时间。</p><p>尊重他人经年累月得出的成果，敬畏你不了解的知识，我也只能这样要求自己。</p><h2 id="杂和一些不成熟的经验"><a class="markdownIt-Anchor" href="#杂和一些不成熟的经验"></a> 杂，和一些不成熟的经验</h2><p>今年是在美国的第4年，很多朋友都回国，或准备回国了。</p><p>想着自己还要在美国呆上至少5年，心里确实很寂寞。</p><p>写到这里就不知道说什么了，希望大家都好吧。我能期盼的就是接下来的若干年里我每年都有时间回一趟国。</p><p>这一年里的大多不高兴也大多是由于老板引起的。</p><p>我觉得如果有缘人会读到这里，并且恰巧要申请PhD，我想分享一下关于我对于和导师相处的经验：</p><ol><li>不要只选择中国导师。是的，也许你会更容易拿到offer，但从我身边的数据看，中国导师就是普遍要更harsh（注意，不是push）。正常的批评应该虚心接受，但无止境但贬低和负面情绪一定是有害的。请千万不要在被导师贬低的时候陷入无限的自我怀疑。更不要产生负罪感。保持自己的节奏，不要无止境的将时间投入到科研中，不要中了一些内心险恶的人的圈套。</li><li>Don’t be soft。要敢于和老板抗争，要敢于表达自己的不满。要明白，很多老板在PUA你的时候，也是在对你的底线进行一种试探。要在适当的时候清晰的表达你的不满，但不要以愤怒的形式表达出来。一切就事论事，以便于在日后依然保持健康的师生关系。</li><li>在进组之前一定要尽可能和组里的学生取得联系，以此侧面了解情况。更重要的是，对于现在的学生说的话要降低期待。只要不是强烈推荐，那几乎可以肯定这个老板有对学生不好的地方。然后再根据自己的情况做取舍。</li><li>学生之间背景差异比较大的导师往往会更包容，which means 更nice。</li><li>用自己的实力和态度来打动老板，不要靠帮老板搬砖来企图讨好老板。</li></ol><h2 id="最后"><a class="markdownIt-Anchor" href="#最后"></a> 最后</h2><p>终于在临近新年的时候收获了一些好消息。</p><p>当然还有很长的路要走，把自己的所有愿望放在心里，然后期待2021。</p>]]></content:encoded>
      
      
      
      <category domain="https://funemy.github.io/tags/annual-review/">annual review</category>
      
      
      <comments>https://funemy.github.io/2020/12/28/2020-12-28-annual-review/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Data Races, what are they, and why are they evil?</title>
      <link>https://funemy.github.io/2020/08/01/2020-8-1-datarace/</link>
      <guid>https://funemy.github.io/2020/08/01/2020-8-1-datarace/</guid>
      <pubDate>Sat, 01 Aug 2020 23:10:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;h3 id=&quot;race-conditions-and-data-races&quot;&gt;&lt;a class=&quot;markdownIt-Anchor&quot; href=&quot;#race-conditions-and-data-races&quot;&gt;&lt;/a&gt; Race Conditions and Data</description>
          
        
      
      
      
      <content:encoded><![CDATA[<h3 id="race-conditions-and-data-races"><a class="markdownIt-Anchor" href="#race-conditions-and-data-races"></a> Race Conditions and Data Races</h3><p>It is commonly known that writing concurrent programs can introduce a kind of bug that normally does not exist in single-threaded programs. Many people refer to them as “Races”, or “Race Conditions”.</p><p>You may also hear about people talking about a kind of bug called “Data Races”. For example, the simulation program for the COVID-19 pandemic was <a href="https://github.com/mrc-ide/covid-sim/issues/161">questioned</a> about their correctness because of suspected potential “data races”. The discussions have caused quite some drama online.</p><p>So are data races the same as race conditions, given that they both share “race” in their names and have similar code patterns? This confuses a lot of people, and even some experienced developers.</p><p>Simply put, race conditions and data races are different. One is not even a subset of the other, which is a common <a href="https://stackoverflow.com/questions/11276259/are-data-races-and-race-condition-actually-the-same-thing-in-context-of-conc">misunderstanding</a>.</p><p>Race condition, according to its <a href="https://en.wikipedia.org/wiki/Race_condition">wiki page</a>:</p><blockquote><p>… is the condition of an electronics, software, or other system where the system’s substantive behavior is dependent on the sequence or timing of other uncontrollable events. It becomes a bug when one or more of the possible behaviors is undesirable.</p></blockquote><p>This definition implies race condition is not inherently a bug. Race conditions are inevitable as long as concurrent events exist in the system. Consider the following example:</p><figure class="highlight gml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// x is a shared variable</span></span><br><span class="line"><span class="comment">// Thread 1</span></span><br><span class="line"><span class="variable language_">x</span> = <span class="number">1</span></span><br><span class="line">print <span class="variable language_">x</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Thread 2</span></span><br><span class="line"><span class="variable language_">x</span> = <span class="number">999</span></span><br></pre></td></tr></table></figure><p>There is clearly a race condition going on, where the result of <code>print x</code> is dependent on the sequence of assignments to <code>x</code>. However, whether it is a bug really depends on what we expect to be printed out, i.e., if the behavior is “desired”.</p><p>On the other hand, data race is clearly defined as a <strong>bug</strong>. Data race occurs when two memory accesses:</p><ul><li>are accessing the same piece of memory;</li><li>are performed concurrently;</li><li>have at least one write;</li><li>are not protected by synchronization or locks.</li></ul><p>The definition of “concurrently” is language-dependent. For example, the C++ Standard defines two actions as potentially concurrent if:</p><ul><li>they are performed by different threads, or</li><li>they are unsequenced, and at least one is performed by a signal handler.</li></ul><p>The second rule is <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf">idiosyncratic to C++</a>. The Java Language Specification gives a different <a href="https://docs.oracle.com/javase/specs/jls/se12/html/jls-17.html#jls-17.4.5">definition</a>.</p><p>Now re-examining the example above, we find it is also a “data race”. The concurrent accesses of <code>x</code> are unprotected, so it is a <strong>BUG</strong>!</p><p>A valid fix for this bug is to simply protect each access with a lock:</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// x is a shared variable</span></span><br><span class="line"><span class="comment">// l is a global lock</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Thread 1</span></span><br><span class="line"><span class="function"><span class="title">lock</span><span class="params">(l)</span></span></span><br><span class="line"><span class="attribute">x</span> = <span class="number">1</span></span><br><span class="line"><span class="function"><span class="title">unlock</span><span class="params">(l)</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">lock</span><span class="params">(l)</span></span></span><br><span class="line">print <span class="attribute">x</span></span><br><span class="line"><span class="function"><span class="title">unlock</span><span class="params">(l)</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// Thread 2</span></span><br><span class="line"><span class="function"><span class="title">lock</span><span class="params">(l)</span></span></span><br><span class="line"><span class="attribute">x</span> = <span class="number">999</span></span><br><span class="line"><span class="function"><span class="title">unlock</span><span class="params">(l)</span></span></span><br></pre></td></tr></table></figure><p>Now, all data races in this example are gone, but a race condition still exists. The critical sections (the code segment between a pair of lock and unlock) are still unsequenced. The code can still be buggy, say if printing out “999” is undesirable.</p><h3 id="benign-or-non-benign-where-lies-the-evilness"><a class="markdownIt-Anchor" href="#benign-or-non-benign-where-lies-the-evilness"></a> Benign or non-benign? Where lies the evilness?</h3><p>Let’s suppose printing out “999” is indeed a buggy behavior.</p><p>Clearly, the buggy printing of “999” is not introduced by the data race but the race condition. To get rid of the bug, we can either <em>a)</em> join thread 2 before the write operation to <code>x</code> in thread 1; or <em>b)</em> put the two operations on <code>x</code> in thread 1 into the same critical section. Both fixes ensure there could be no unexpected operation between <code>x = 1</code> and <code>print x</code>.</p><p>Now One observation you might have is, fixing data races does not necessarily eliminate the race conditions. If so, <strong>what is the harm actually brought by a data race? Why we want to get rid of them?</strong></p><p>Before we step into the evil world of data races, let’s first take a step back to understand a concept: <strong>“benign data race”</strong>. There is a widely held and strong perception that data races are acceptable in certain contexts, and thus are commonly used in existing code.</p><p>This turns out to be very wrong. Not only are those benign data races technically incorrect and harmful, but new bugs may be introduced by future re-compilation if the code is meant to be portable.</p><p>I present some common C/C++ “benign” patterns from a <a href="https://www.usenix.org/legacy/event/hotpar11/tech/final_files/Boehm.pdf">paper</a> by Hans-J. Boehm below, and briefly explain how those common patterns could go wrong:</p><ol><li><em>Double-checked locking</em></li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (!init_flag) &#123;</span><br><span class="line">    lock(); </span><br><span class="line">    <span class="keyword">if</span> (!init_flag) &#123;</span><br><span class="line">        my_data = ...;</span><br><span class="line">        init_flag = <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    unlock(); </span><br><span class="line">&#125; </span><br><span class="line">tmp = my_data;</span><br></pre></td></tr></table></figure><p>This is a very famous pattern (known as DCLP), and is also well-known to be incorrect. The code is potentially buggy if compiler optimization or hardware reordering is applied (which they are, in most real cases).</p><p>For example, there’s nothing to prevent the compiler from advancing <code>init_flag = true</code> before the setting of <code>my_data</code>. Assuming there are two threads executing the code above, the second thread may end up reading an uninitialized value (because <code>init_flag</code> is set to <code>true</code> before <code>my_data</code> get initialized).</p><p>A general solution for this pattern does not exist until Java 1.5 (the <code>volatile</code> keyword) and C++11 (the memory fence). Without these, we have to protect the whole pattern with a lock, which in turn brings a performance degradation.</p><p>For more details about DCLP, you can check the <a href="https://en.wikipedia.org/wiki/Double-checked_locking">wiki</a>, this <a href="http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html">page</a> for Java, and Scott and Andrei’s <a href="https://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf">paper</a> about C++.</p><ol start="2"><li><em>Reading imprecise value is allowed</em></li></ol><p>There are cases where a read from a thread does not care about if another thread has updated the value or not, i.e., either the old value or the new value results in a valid computation. In such cases, are data races benign?</p><p>The answer, of course, is <strong>NO</strong>. Simply because data races will potentially cause the read operation to obtain a meaningless value that doesn’t correspond to either the old value nor the new value.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Read global</span></span><br><span class="line"><span class="type">int</span> my_counter = counter;</span><br><span class="line"><span class="type">int</span> (* my_func) (<span class="type">int</span>);</span><br><span class="line"><span class="keyword">if</span> (my_counter &gt; my_old_counter) &#123;</span><br><span class="line">    ...</span><br><span class="line">    my_func = ...;</span><br><span class="line">&#125;</span><br><span class="line">...</span><br><span class="line"><span class="keyword">if</span> (my_counter &gt; my_old_counter) &#123;</span><br><span class="line">    ... </span><br><span class="line">    my_func(...) </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Consider the code pattern on the above, where <code>my_counter</code> reads from a global variable <code>counter</code> without protection. The global counter may get updated by some other threads running in parallel. Here the developer may think reading an old value of counter is fine due to the if <code>(my_counter &gt; my_old_counter)</code> check.</p><p>However, if the compiler thinks the register of <code>my_counter</code> needs to be spilled between the two if-checks, then it is legit to re-read <code>my_counter</code>‘s value again to avoid spilling, as shown on the below. Now under this optimized code, the two if-checks may not yield the same result, which can lead to unexpected behavior when calling <code>my_func</code>.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Read global</span></span><br><span class="line"><span class="type">int</span> my_counter = counter;</span><br><span class="line"><span class="type">int</span> (* my_func) (<span class="type">int</span>);</span><br><span class="line"><span class="keyword">if</span> (my_counter &gt; my_old_counter) &#123;</span><br><span class="line">    ...</span><br><span class="line">    my_func = ...;</span><br><span class="line">&#125;</span><br><span class="line">...</span><br><span class="line"><span class="comment">// ANOTHER read global</span></span><br><span class="line"><span class="type">int</span> my_counter = counter;</span><br><span class="line"><span class="keyword">if</span> (my_counter &gt; my_old_counter) &#123;</span><br><span class="line">    ... </span><br><span class="line">    my_func(...) </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>If we go a bit further to the hardware level. Assuming we want to maintain an imprecise global 64-bit integer <code>counter</code>. We make the <code>counter++</code> concurrent and unprotected. If your system only supports 32-bit indivisible writes, then once a thread is updating the counter value from <code>2^32 - 1</code> to <code>2^32</code>, another thread could read a value whose higher bits are already updated but lower bits are not. This will make the counter value totally meaningless.</p><ol start="3"><li><em>Incorrect ad hoc synchronizations</em></li></ol><p>Ad hoc (or user constructed) synchronizations should not use ordinary operations. Otherwise, we will generally face issues similar to what is mentioned above.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// `flag` is intended to be an ad hoc lock</span></span><br><span class="line"><span class="keyword">while</span> (!flag) &#123;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// compiler optimized code</span></span><br><span class="line">tmp = flag</span><br><span class="line"><span class="keyword">while</span> (!tmp) &#123;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>For example, the busy-waiting loop above can be optimized to something like the second code snippet, due to register spilling. The optimized loop might run indefinitely under concurrent execution, yet it is equivalent to the example on top under sequential code.</p><p>Or if we want to use a busy-waiting loop as a memory barrier, like the example below:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span> (!flag) &#123;&#125;; <span class="comment">// waiting for `data` to be updated</span></span><br><span class="line">tmp = data;</span><br></pre></td></tr></table></figure><p>Compiler or hardware could potentially reverse the order of the two instructions. Thus, this ad hoc memory barrier is mostly meaningless.</p><ol start="4"><li><em>Redundant write</em></li></ol><p>Assume we have a function f(x):</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// count is a shared variable between threads</span></span><br><span class="line">f(x) &#123;</span><br><span class="line">    ...;</span><br><span class="line">    <span class="keyword">for</span> (p = x; p != <span class="number">0</span>; p = p -&gt; next) &#123;</span><br><span class="line">        <span class="keyword">if</span> (p-&gt;data &lt; <span class="number">0</span>) count++;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Notice that count is a shared variable, and it’s only updated when p has negative value. Now if we use this function in the following way:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Thread 1</span></span><br><span class="line">count = <span class="number">0</span>;</span><br><span class="line">f(positives);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Thread 2</span></span><br><span class="line">f(positives);</span><br><span class="line">count = <span class="number">0</span>;</span><br></pre></td></tr></table></figure><p>The argument <code>positives</code> is a linked list whose nodes only contain positive value. Hence, there’s only one data race between the two <code>count = 0</code> instructions. You may wonder, how could this possibly go wrong, since all we are doing is writing the same value to count repeatedly.</p><p>However, things become different if the compiler inlines <code>f(positives)</code> and promote the variable count to a thread-local register (this is legitimate because count is written unconditionally). Now the actual instructions being executed by each thread become something like below:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Thread 1</span></span><br><span class="line">count = <span class="number">0</span>; <span class="comment">// step 2</span></span><br><span class="line">reg1 = count <span class="comment">// step 4</span></span><br><span class="line">count = reg1 <span class="comment">// step 6</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Thread 2</span></span><br><span class="line">reg2 = count; <span class="comment">// step 1</span></span><br><span class="line">count = reg2; <span class="comment">// step 3</span></span><br><span class="line">count = <span class="number">0</span>; <span class="comment">// step 5</span></span><br></pre></td></tr></table></figure><p>Now under this specific interleaving, we find it is possible for count to remain its original value instead of being zeroed out.</p><ol start="5"><li><em>Disjoint bit manipulation</em></li></ol><p>This kind of “benign” data races are <a href="https://cseweb.ucsd.edu/~calder/papers/PLDI-07-DataRace.pdf">described</a> as:</p><blockquote><p>… data races between two memory operations where the programmer knows for sure that the two operations use or modify different bits in a shared variable.</p></blockquote><p>Those kinds of manipulation are not generally benign. Updating bits usually contains <em>a)</em> Reading the whole value; <em>b)</em> Updating the relevant bits; and <em>c)</em> Writing the value back. We can clearly see specific interleaving may cause some updates to be invalid.</p><p>Even in the case when there is only 1 thread updating the bits, we can come up with the following example:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">x.bits1 = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">switch</span>(i) &#123;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">        x.bits2 = <span class="number">1</span>;</span><br><span class="line">        ...;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line">        x.bits2 = <span class="number">1</span>;</span><br><span class="line">        ...;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line">        ...;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">default</span>:</span><br><span class="line">        x.bits2 = <span class="number">1</span>;</span><br><span class="line">        ...;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Our original code is shown above. <code>x</code> is a global variable whose bits represent different flags, and <code>bits1</code> and <code>bits2</code> are two bit fields of <code>x</code>.</p><p>Notice that in our original code, <code>case 3</code> does not update <code>x.bits2</code> and it happens to be the branch we are using (assume this is a fact compiler does not know, so that the other branches will not be pruned). Now if we have a second thread only reading the value of <code>x.bits2</code>. This seems to be a perfectly safe situation.</p><p>However, existing compilers may consider adjacent bit-fields as belonging to the same memory location (here in our case, <code>x.bits1</code> and <code>x.bits2</code>). The write to <code>x.bits1</code> will make the compiler think the target memory location is data-race free, thus justify its optimizations on <code>x.bits2</code>. This leads to the optimized code shown on below, where the potential updates on <code>x.bits2</code> are advanced to shrink the code size (if we have more branches that update <code>x.bits2</code>). Now if we are still using <code>case 3</code>, the read from other thread will conflict with the write on <code>case 3</code>, causing the second thread to read invalid values of <code>x.bits2</code>.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">x.bits1 = <span class="number">1</span>;</span><br><span class="line">tmp = x.bits2</span><br><span class="line">x.bits2 =<span class="number">1</span></span><br><span class="line"><span class="keyword">switch</span>(i) &#123;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">        ...;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line">        ...;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line">        x.bits2 = tmp;</span><br><span class="line">        ...;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">default</span>:</span><br><span class="line">        ...;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>To sum up</strong>, the evilness of data races mostly lies in compiler optimizations, hardware reordering, and underlying memory models. Most compiler optimizations assume the program is data-race free, thus compilers may introduce <strong>undefined behaviors</strong> when data races exist. The worst thing about undefined behavior is it could lead to any actions (such as launching a missile?) instead of just entering an invalid path of your program.</p><p>If you are interested in reading more discussion related to data races, there’s another <a href="https://software.intel.com/content/www/us/en/develop/blogs/benign-data-races-what-could-possibly-go-wrong.html">blog</a> explaining this.</p><h3 id="how-do-i-prevent-my-program-from-launching-missiles-unexpectedly"><a class="markdownIt-Anchor" href="#how-do-i-prevent-my-program-from-launching-missiles-unexpectedly"></a> How do I prevent my program from launching missiles unexpectedly?</h3><p>If you make it here, hopefully you are not terrified by what can be caused by data races. Just to be fair, there could be “benign” data races under more concrete contexts, such as knowing the specific architecture, compiler version, optimization passes used and the memory models, and the code is not intended to be portable.</p><p>Nevertheless, I strongly believe developers should pay more attention to potential data races just like how they treat compiler warnings (I feel terribly sorry for you if you don’t).</p><p>Properly protecting concurrent shared memory accesses not only prevent programs from all those subtle bugs we presented above, but also significantly increase the readability for your code by specifying their concurrent semantics. Besides, there are tools like <a href="https://clang.llvm.org/docs/ThreadSanitizer.html">ThreadSanitizer</a>, <a href="https://software.intel.com/content/www/us/en/develop/tools/inspector.html">Intel Inspector</a>, and <a href="https://coderrect.com/">Coderrect Racedetector</a> to efficiently reveal potential data races at different programming phases.</p><p>Let’s just not making our software program to be a missile launcher, :=).</p>]]></content:encoded>
      
      
      
      <category domain="https://funemy.github.io/tags/concurrency/">concurrency</category>
      
      
      <comments>https://funemy.github.io/2020/08/01/2020-8-1-datarace/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>if-else branch without if</title>
      <link>https://funemy.github.io/2019/01/29/2019-01-29-ifbranch/</link>
      <guid>https://funemy.github.io/2019/01/29/2019-01-29-ifbranch/</guid>
      <pubDate>Tue, 29 Jan 2019 15:02:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math</description>
          
        
      
      
      
      <content:encoded><![CDATA[<p class='katex-block'><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mtable rowspacing="0.24999999999999992em" columnalign="right left" columnspacing="0em"><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mi>t</mi><mi>r</mi><mi>u</mi><mi>e</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><mi>λ</mi><mi>x</mi><mi mathvariant="normal">.</mi><mi>λ</mi><mi>y</mi><mi mathvariant="normal">.</mi><mi>x</mi></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mi>f</mi><mi>a</mi><mi>l</mi><mi>s</mi><mi>e</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><mi>λ</mi><mi>x</mi><mi mathvariant="normal">.</mi><mi>λ</mi><mi>y</mi><mi mathvariant="normal">.</mi><mi>y</mi></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mi>i</mi><mi>f</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><mi>λ</mi><mi>x</mi><mi mathvariant="normal">.</mi><mi>λ</mi><mi>y</mi><mi mathvariant="normal">.</mi><mi>λ</mi><mi>z</mi><mi mathvariant="normal">.</mi><mi>x</mi><mo stretchy="false">(</mo><mi>y</mi><mo stretchy="false">)</mo><mo stretchy="false">(</mo><mi>z</mi><mo stretchy="false">)</mo></mrow></mstyle></mtd></mtr></mtable><annotation encoding="application/x-tex">\begin{aligned}true &amp;= \lambda x. \lambda y. x \\false &amp;= \lambda x. \lambda y. y \\if &amp;= \lambda x. \lambda y. \lambda z. x (y) (z)\end{aligned}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:4.500000000000002em;vertical-align:-2.000000000000001em;"></span><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.5000000000000004em;"><span style="top:-4.66em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">t</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">u</span><span class="mord mathnormal">e</span></span></span><span style="top:-3.16em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">s</span><span class="mord mathnormal">e</span></span></span><span style="top:-1.6599999999999993em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">i</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:2.000000000000001em;"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.5000000000000004em;"><span style="top:-4.66em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord mathnormal">λ</span><span class="mord mathnormal">x</span><span class="mord">.</span><span class="mord mathnormal">λ</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord">.</span><span class="mord mathnormal">x</span></span></span><span style="top:-3.16em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord mathnormal">λ</span><span class="mord mathnormal">x</span><span class="mord">.</span><span class="mord mathnormal">λ</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord">.</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span></span></span><span style="top:-1.6599999999999993em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord mathnormal">λ</span><span class="mord mathnormal">x</span><span class="mord">.</span><span class="mord mathnormal">λ</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord">.</span><span class="mord mathnormal">λ</span><span class="mord mathnormal" style="margin-right:0.04398em;">z</span><span class="mord">.</span><span class="mord mathnormal">x</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mclose">)</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.04398em;">z</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:2.000000000000001em;"><span></span></span></span></span></span></span></span></span></span></span></span></p>]]></content:encoded>
      
      
      
      <category domain="https://funemy.github.io/tags/functional-programming/">functional programming</category>
      
      <category domain="https://funemy.github.io/tags/lambda-calculus/">lambda calculus</category>
      
      
      <comments>https://funemy.github.io/2019/01/29/2019-01-29-ifbranch/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Use python generator to solve yin-yang puzzle</title>
      <link>https://funemy.github.io/2018/08/30/2018-08-30/</link>
      <guid>https://funemy.github.io/2018/08/30/2018-08-30/</guid>
      <pubDate>Thu, 30 Aug 2018 10:50:00 GMT</pubDate>
      
      <description>&lt;p&gt;An interesting solution of yin-yang puzzle, and create the universe (笑）&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>An interesting solution of yin-yang puzzle, and create the universe (笑）</p><span id="more"></span><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">yin</span>(<span class="params">cb1</span>):</span><br><span class="line"><span class="keyword">yield</span> <span class="string">&#x27;@&#x27;</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">yang</span>(<span class="params">cb2</span>):</span><br><span class="line"><span class="keyword">yield</span> <span class="string">&#x27;*&#x27;</span></span><br><span class="line"><span class="keyword">yield</span> <span class="keyword">from</span> cb1(cb2)</span><br><span class="line"><span class="keyword">yield</span> <span class="keyword">from</span> yang(yang)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">puzzle</span>():</span><br><span class="line"><span class="keyword">yield</span> <span class="keyword">from</span> yin(yin)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> x, _ <span class="keyword">in</span> <span class="built_in">zip</span>(puzzle(), <span class="built_in">range</span>(<span class="number">50</span>)):</span><br><span class="line"><span class="built_in">print</span>(x, end=<span class="string">&#x27;&#x27;</span>)</span><br></pre></td></tr></table></figure><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@<span class="emphasis">*@<span class="strong">**@**</span>*</span>@<span class="strong">****</span>@<span class="strong">****</span><span class="emphasis">*@<span class="strong">****</span><span class="strong">**@**</span><span class="strong">****</span>*</span>@<span class="strong">****</span><span class="strong">****</span>@<span class="strong">****</span><span class="emphasis">*</span></span><br></pre></td></tr></table></figure><p>Each time the prgram will output an extra <code>*</code> symbol, therefore our universe is created.</p><p>This puzzle is a famous one in functional programming area (probably?). Notably solved by utilizing <code>call/cc</code> (<a href="https://en.wikipedia.org/wiki/Call-with-current-continuation">continuation</a>).</p><p>As we all know, python’s <code>generator</code> is no more than a simplified version of continuation. And that’s where the solution comes from.</p><p>An interesting question here is why there’s an increment on <code>*</code> symbol.</p><p>The key to understanding this is noticing the <strong>context</strong> carried with each generator. To make everything clear, we use notation like <code>yin_yang~yin</code>. The name befoere <code>_</code> indicates the generator name we are currently calling, the sequence after <code>_</code> indicates the value of <code>cb1</code> in the nested context, from the nearest to the furthest.</p><p>Here we only need to care about <code>cb1</code> (callback 1), since it is the place where magic happens. For <code>cb2</code>, since we only call <code>yang(yang)</code>, it just duplicates itself every time.</p><p>Then we can interpret the process in the following way:</p><figure class="highlight livescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">yin(yin) <span class="string">\\</span> @</span><br><span class="line">-&gt; yang_yin(yang_yin) <span class="string">\\</span> *</span><br><span class="line">-&gt; yin(yang_yin) <span class="string">\\</span> @</span><br><span class="line">-&gt; yang_yang~yin(yang_yang~yin) <span class="string">\\</span> *</span><br><span class="line">-&gt; yang_yin(yang_yang~yin) <span class="string">\\</span> *</span><br><span class="line">-&gt; yin(yang_yang~yin) <span class="string">\\</span> @</span><br><span class="line">-&gt; yang_yang~yang~yin(yang_yang~yang~yin)</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>We can see how the context grows. The key here is, even though we are always passing <code>yang</code> to <code>cb1</code>, the context carried with each <code>yang</code> is different.</p><p>If this explaination is not clear enough for you, a comprehensive scheme version explaination is available <a href="https://stackoverflow.com/questions/2694679/how-does-the-yin-yang-puzzle-work">here</a>.</p>]]></content:encoded>
      
      
      
      <category domain="https://funemy.github.io/tags/python/">python</category>
      
      <category domain="https://funemy.github.io/tags/functional-programming/">functional programming</category>
      
      
      <comments>https://funemy.github.io/2018/08/30/2018-08-30/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Restarting my blog</title>
      <link>https://funemy.github.io/2018/05/22/2018-05-22-restart/</link>
      <guid>https://funemy.github.io/2018/05/22/2018-05-22-restart/</guid>
      <pubDate>Tue, 22 May 2018 14:36:00 GMT</pubDate>
      
      <description>&lt;p&gt;Think about re-starting my blog&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>Think about re-starting my blog</p><span id="more"></span><p>Haven’t written blog for a looooooong time and so many things happened since my graduation.</p><p>Started joining Jeff’s lab recently, life will start to become regular (hopfully?).</p><p>This time I’ll try to write my blog in English, just to record my life a little bit.</p>]]></content:encoded>
      
      
      
      <category domain="https://funemy.github.io/tags/random/">random</category>
      
      
      <comments>https://funemy.github.io/2018/05/22/2018-05-22-restart/#disqus_thread</comments>
      
    </item>
    
  </channel>
</rss>
