<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>RiversJin's Blog</title><link>https://riversjin.github.io/</link><description>Recent content on RiversJin's Blog</description><generator>Hugo</generator><language>zh</language><lastBuildDate>Wed, 01 Nov 2023 00:00:00 +0800</lastBuildDate><atom:link href="https://riversjin.github.io/index.xml" rel="self" type="application/rss+xml"/><item><title>Rust 中的逆变与协变</title><link>https://riversjin.github.io/posts/rust-variance-lifetime/</link><pubDate>Wed, 01 Nov 2023 00:00:00 +0800</pubDate><guid>https://riversjin.github.io/posts/rust-variance-lifetime/</guid><description>&lt;p>subtyping 在编程理论中, 是一个很有趣的话题.
Rust虽然并不那么OOP, 但是其生命周期系统依然会有逆变,协变以及子类型的概念.&lt;/p>
&lt;h2 id="逆变--协变">逆变 &amp;amp;&amp;amp; 协变&lt;/h2>
&lt;p>让我们忘掉Rust, 先来复习一下逆变与协变的概念. 为了简化描述, 我们来定义一下下面的记号&lt;/p>
&lt;blockquote>
&lt;p>&lt;code>A &amp;lt;: B&lt;/code> 代表A是B的子类型
&lt;code>A -&amp;gt; B&lt;/code> 以 &lt;code>A&lt;/code> 为参数类型, 以 &lt;code>B&lt;/code> 为返回值类型的&lt;strong>函数类型&lt;/strong>
&lt;code>x : A&lt;/code> x是一个变量, 其类型为A&lt;/p>&lt;/blockquote>
&lt;p>我们有三个类型 &lt;code>Greyhound &amp;lt;: Dog &amp;lt;: Animal&lt;/code>&lt;/p>
&lt;p>&lt;code>Greyhound&lt;/code> 是 &lt;code>Dog&lt;/code> 的子类型 (或者说 &lt;code>Greyhound&lt;/code> 是 &lt;code>Dog&lt;/code> 的一种); &lt;code>Dog&lt;/code> 是 &lt;code>Animal&lt;/code> 的子类型 ( &lt;code>Dog&lt;/code> 是 &lt;code>Animal&lt;/code> 的一种).&lt;/p>
&lt;p>从概念上讲, 子类型至少有着父类型的全部内涵(或者说特性), 并且可能还会多一些.&lt;/p>
&lt;blockquote>
&lt;p>所以很显然 A &amp;lt;: A 是成立的. A当然至少有着A的全部特性. 这是一种大于等于的关系&lt;/p>&lt;/blockquote>
&lt;p>协变(Covariance)是指子类向基类的转换.&lt;/p>
&lt;p>比如我需要一个 &lt;code>Dog&lt;/code>, 但是你给了我一个 &lt;code>Greyhound&lt;/code>, 这样我获得的不仅是 &lt;code>Dog&lt;/code>, 甚至还有更多的特性(灰毛). 这种情形就是&lt;strong>协变&lt;/strong>&lt;/p></description></item><item><title>记一次使用 Musl 全静态化编译 C++ 程序的过程</title><link>https://riversjin.github.io/posts/musl-static-link-cpp/</link><pubDate>Sun, 01 Oct 2023 00:00:00 +0800</pubDate><guid>https://riversjin.github.io/posts/musl-static-link-cpp/</guid><description>&lt;p>容我先吐槽一下某&amp;quot;互联网大公司&amp;quot;, 不然难解我心头之恨.
现在是2023年, CentOS6是2011年发布的, 我2011年还是上小学的小屁孩, 十多年过去了, 我大学毕业参加工作, 还能被CentOS6折磨到破防, 这是怎样一个神奇妙妙旅程.
更别提还有用Linux 4.18强行装到CentOS7上的离谱行为, 内核用的是新的, Glibc用的是旧的, 我真想不明白图什么. 图稳定? CentOS, 不过一个雨林木风版的RHEL, 没了背后的红帽, 好像有问题自己真能修一样, 乐.&lt;/p>
&lt;p>事情是这样的, 线上机器有很大一批用的还是CentOS6, Glibc2.10的系统环境. 由于一批机型磁盘大小比较小, 而程序又依赖RocksDB存储数据, 恰好最近数据变动比较多, LSM占用了太多空间导致磁盘容量告急.&lt;/p>
&lt;p>为了让程序不至于完全写满硬盘导致服务不可用, 只能想办法先手动合并一次RocksDB, 清除无用数据释放空间.&lt;/p>
&lt;blockquote>
&lt;p>什么? 你问我为什么程序自身没有主动合并的逻辑? 为什么没有配置Rocksdb主动合并? 我只是个接盘的倒霉蛋, 我怎么知道.&lt;/p>&lt;/blockquote>
&lt;p>既然程序自身没有这个逻辑, 我的计划是自己简单写一个小工具, 调用Rocksdb接口, 触发一次手动合并即可. 但是新的问题出现了, 现在几乎找不到CentOS6的软件源了, 我没办法配置一套与服务器一致的开发环境.&lt;/p>
&lt;p>在网上搜索的过程中, 看到了Uber使用zig提供的工具链, 可以实现完全&amp;quot;封闭&amp;quot;的编译链接过程, 完全不依赖外部环境, zig可以把自己伪装成一个c/c++的编译器, 并且允许你指定任何编译平台目标, 包括CPU平台, 操作系统, 标准库版本.&lt;/p>
&lt;p>这我也是试过的, 但是在glib2.10面前, 都是弟弟. zig的c/c++编译功能实际上就是封装了clang, 而clang++的C++标准库libc++, 又直接依赖glibc2.15的一个接口, 此路不通.&lt;/p>
&lt;p>那么剩下就没什么可选的了, 静态编译, 启动! 如果出现了老内核无法支持的系统调用, 那我也没什么好办法了, 人和代码总要有一个能跑, 代码不行的话, 那就是我了.&lt;/p>
&lt;p>但是, 试过就知道, 想要静态链接glibc库, 问题很多, 你会见到各种莫名其妙的问题, 我这里就不一一说明了, 总之难度很高.&lt;/p></description></item><item><title>用宏实现一个智能指针</title><link>https://riversjin.github.io/posts/c-macro-smart-pointer/</link><pubDate>Fri, 01 Sep 2023 00:00:00 +0800</pubDate><guid>https://riversjin.github.io/posts/c-macro-smart-pointer/</guid><description>&lt;h1 id="background">Background&lt;/h1>
&lt;p>作为一个从C++入门学习编程的人, 没有GC, 但是一直以来Cpp的智能指针用着还算顺手. 但是这一切美好都被工作时遇到的纯C代码给破坏了.
由于前人的肆意挥洒, 这坨号称是C的克苏鲁已经彻底与CPP分道扬镳, 无法再享受C++与C的兼容性.
用Rust的bindgen也许可以让这坨十年前的古董也享受一下现代编程语言的发展, 无奈周围的人无人肯学 :(&lt;/p>
&lt;p>但是, 日子总还得过. 上帝说过, 使用泛型容器是每个人自由而平等的权力, 不容侵犯.
况且即使是C, 也总有引用计数, 数据结构容器的需求.
所以, 在与命运抗争的不甘之下, 我开始尝试用宏在C泛型容器. 经过尝试发现并不难, 就是有点丑, 不太优雅, 但多少也能凑合着用.
这篇文章, 我们以宏实现一个shared_ptr. 来探讨一下宏的能力, 以及复习一下基于引用计数的智能指针都有哪些功能.&lt;/p>
&lt;h1 id="宏-macro">宏 Macro&lt;/h1>
&lt;p>C的宏功能很弱, 基本就是个文本替换, 也不是什么图灵完全的, 能力很有限. 但是有一些很有趣的用法&lt;/p>
&lt;p>一个&amp;quot;#&amp;ldquo;代表&amp;quot;Stringizing&amp;rdquo; 字符串化, 它可以将后面的宏参数变为一个字面量字符串, 比如&lt;/p>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#define str(s) xstr(s)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#define xstr(s) #s
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// str(abc) 会被展开为 &amp;#34;abc&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>这里有一个地方也很有趣, 明明是 &lt;code>#define str(s) #s&lt;/code> 似乎就可以了, 但是我们还是需要两个宏才行.
这就是我之前说的, C的宏很弱, 它执行的只是文本替换.&lt;/p></description></item><item><title>自己动手，实现一个有栈协程 (Linux AMD64)</title><link>https://riversjin.github.io/posts/stackful-coroutine-linux-amd64/</link><pubDate>Tue, 01 Aug 2023 00:00:00 +0800</pubDate><guid>https://riversjin.github.io/posts/stackful-coroutine-linux-amd64/</guid><description>&lt;p>我之前的文章中, 曾经介绍过无栈协程是如何实现的. 通常来说, 无栈协程需要编译器辅助将异步函数切分成多个&amp;quot;块&amp;quot;, 如果没有编译器的帮忙的话, 通常我们会将这种无栈协程称为&amp;mdash;-有限状态机.&lt;/p>
&lt;p>这次, 我们来实现一个简单的有栈协程. 与无栈协程不同, 有栈协程的侵入性会小很多, 不需要编译器的帮忙, 只需要自己实现一点点汇编, 即可实现.&lt;/p>
&lt;blockquote>
&lt;p>那么, 古尔丹, 代价是什么?
是性能, 由于有栈协程在切换时会&amp;quot;非正常&amp;quot;地修改执行流, 以及栈空间. 会导致CPU流水线产生大量stall以及缓存miss.
当然, 如果软件的主要耗时都在IO上面, 那么倒也无所谓, 反正Golang整个就是有栈协程, 也没有慢很多
以及兼容性, 理论上无栈协程是跨平台的, 只要代码能编译, 一套含有无栈协程机制的代码是可以直接在任何平台上运行的. 但是有栈协程需要一点点汇编, 这就必须为每种硬件平台, 每种ABI单独适配.&lt;/p>&lt;/blockquote>
&lt;h1 id="前置知识以amd64-linux平台为例">前置知识(以AMD64, Linux平台为例)&lt;/h1>
&lt;p>注意, 如果你曾经学习过CSAPP这本书, 那么我认为是可以跳过此节, 直接向下看的.&lt;/p>
&lt;p>我们知道, 调用函数时, 会根据调用约定, 将参数放在栈上内存中, 或者依靠寄存器直接传递. 但大体来说的步骤基本就是:&lt;/p>
&lt;ol>
&lt;li>保存场景&lt;/li>
&lt;li>设置参数(通过push放在栈上; 或者按照约定以某种顺序, 放在若干寄存器上)&lt;/li>
&lt;li>调用call 指令, 跳转到指定位置执行.
这里, call指令可以说是汇编的语法糖, 它其实等效于&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>push %rip # 将下一条指令的位置压栈, 即记录函数的返回地址
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mov XXX, %rip # 修改指令寄存器, 跳转到指定位置
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>按照调用约定, 在发生函数调用并返回到原来的位置后, 有些寄存器不能发生变化, 而有些寄存器则不做要求.
前者一般称之为&lt;code>callee-saved registers&lt;/code>, 即被调用函数需要保存寄存器原来的值, 并在返回时恢复.
后者则一般称之为&lt;code>caller-saved register&lt;/code>或者&lt;code>temporary registers&lt;/code>, 即调用者需要自行保存, 在发生函数调用并返回后, 这些寄存器上的值不做任何保证.&lt;/p></description></item><item><title>从 Linux RCU 到 Epoch GC</title><link>https://riversjin.github.io/posts/linux-rcu-to-epoch-gc/</link><pubDate>Sat, 01 Jul 2023 00:00:00 +0800</pubDate><guid>https://riversjin.github.io/posts/linux-rcu-to-epoch-gc/</guid><description>&lt;p>开头先说, 这篇文章没有什么中心思想, 只是为了记录一下我对RCU的理解以及思考. 如有错误偏颇, 欢迎评论指正.&lt;/p>
&lt;h2 id="rcuread-copy-update">RCU(Read-Copy-Update)&lt;/h2>
&lt;p>RCU是Linux中常用的一种同步机制, 用于读多写少的场景. 它的读取很轻量, 几乎没有什么开销, 但是也有一些限制, 它不保证读取到的是最新的数据, 但是保证读取到的数据是合法的.
其实现原理也很简单, 有点类似于无锁链表的实现.&lt;/p>
&lt;p>首先我们知道, CPU可以通过CAS或者类似指令, 实现对于一个64位或者更小数据的原子操作. 如果数据更大一点, 那么就不能直接原子修改掉所有内容, 但是, 我们可以用指针的方式实现.
比如这样&lt;/p>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> Data{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">int64_t&lt;/span> a;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">int64_t&lt;/span> b;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">int64_t&lt;/span> c;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>};
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">struct&lt;/span> Data &lt;span style="color:#f92672">*&lt;/span>data &lt;span style="color:#f92672">=&lt;/span> NULL;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>虽然&lt;code>struct Data&lt;/code>的大小为24字节, 不能直接原子替换, 但是&lt;code>data&lt;/code>作为一个指针, 只有8字节, 对它做原子替换是非常简单的. 所以, 我们只需要让所有需要访问这个结构体的地方, 都使用&lt;code>data&lt;/code>指针, 那么不需要锁, 就做到原子地访问&lt;code>struct Data&lt;/code>了.&lt;/p></description></item><item><title>Rust UnsafeCell VS C++ mutable</title><link>https://riversjin.github.io/posts/rust-unsafecell-cpp-mutable/</link><pubDate>Thu, 15 Jun 2023 00:00:00 +0800</pubDate><guid>https://riversjin.github.io/posts/rust-unsafecell-cpp-mutable/</guid><description>&lt;p>经常在C++中写引用计数的朋友都知道(误), 如果一个class/struct被const修饰, 那么无法修改里面的元素, 但是, 可以通过&lt;code>mutable&lt;/code>修饰某个成员, 相当于开了个洞, 取消掉其const限定, 实现修改被const限定结构体的内部成员.&lt;/p>
&lt;p>这种限制不仅作用于C++类型系统, 同时也会影响C++的代码优化, 我们下面简单举一个例子:&lt;/p>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c++" data-lang="c++">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#include&lt;/span> &lt;span style="color:#75715e">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span style="color:#75715e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#include&lt;/span> &lt;span style="color:#75715e">&amp;lt;fmt/core.h&amp;gt;&lt;/span>&lt;span style="color:#75715e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">using&lt;/span> &lt;span style="color:#66d9ef">namespace&lt;/span> std;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">S&lt;/span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">int&lt;/span> a;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">mutable&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> b;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>};
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">print&lt;/span>(&lt;span style="color:#66d9ef">int&lt;/span> a, &lt;span style="color:#66d9ef">int&lt;/span> b){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cout &lt;span style="color:#f92672">&amp;lt;&amp;lt;&lt;/span> fmt&lt;span style="color:#f92672">::&lt;/span>format(&lt;span style="color:#e6db74">&amp;#34;a = {}, b = {}&amp;#34;&lt;/span>, a, b) &lt;span style="color:#f92672">&amp;lt;&amp;lt;&lt;/span> endl;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">modify_const&lt;/span>(&lt;span style="color:#66d9ef">const&lt;/span> S&lt;span style="color:#f92672">&amp;amp;&lt;/span> s){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> S&lt;span style="color:#f92672">&amp;amp;&lt;/span> m_s &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">const_cast&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>S&lt;span style="color:#f92672">&amp;amp;&amp;gt;&lt;/span>(s);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> m_s.a &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> m_s.b &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">main&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> S s{&lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">1&lt;/span>};
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(s.a, s.b);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> modify_const(s);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(s.a, s.b);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>输出如下&lt;/p></description></item><item><title>C, C++ inline 关键字差异</title><link>https://riversjin.github.io/posts/c-cpp-inline-diff/</link><pubDate>Thu, 01 Jun 2023 00:00:00 +0800</pubDate><guid>https://riversjin.github.io/posts/c-cpp-inline-diff/</guid><description>&lt;p>注: 在C89(ANSI C)中, 是没有inline的, gun的c扩展支持类似于C++的inline语义, 但那是非标准情况, 不属于这里的讨论范围.&lt;/p>
&lt;h1 id="c-c11">C++ (C++11)&lt;/h1>
&lt;p>C++的inline并不是建议编译器内联, 实际上它是告诉编译器, 此符号可能在多个翻译单元中存在, 如果发生重复, 不会发生错误, 而是在最终链接产物时, 只保留其中一个.
通过这个功能, 我们才得以在C++头文件定义模板而无需担心多个cpp文件由于模板实例化导致符号冲突. 这会实现某种意义上的&amp;quot;去重&amp;quot;.
而至于是否内联, 则取决于编译器自身的优化逻辑.&lt;/p>
&lt;h1 id="c99">C99&lt;/h1>
&lt;h2 id="inline">inline&lt;/h2>
&lt;p>C语言的inline与C++的并不相同, 它更多是一种类似于C++&amp;ldquo;模板&amp;quot;的特性.
当一个函数被声明为inline修饰, 像&lt;/p>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">inline&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">foo&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#ae81ff">42&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>这会使得在obj文件, 并不没有foo函数这么一个存在.
它指的是, &lt;strong>如果编译器决定将foo内联&lt;/strong>, 那么会将&lt;code>inline int foo(){...}&lt;/code>内的函数体内联进去.
但如果编译器选择不内联foo, 那么编译器会忽略&lt;code>inline int foo(){...}&lt;/code>的实现, 而是转而假设这是一个外部的符号.
但如果其他obj文件也没有导出foo这么个函数, 那么就会在链接时喜提&lt;code>undefined symbol&lt;/code>错误&lt;/p>
&lt;p>这也就有一个很有趣的现象, 在C中, 通过inline与非inline, 实际上是可以定义出一模一样的两个函数来的:&lt;/p>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/* foo.c */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">foo&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#ae81ff">41&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/* main.c */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#include&lt;/span> &lt;span style="color:#75715e">&amp;lt;stdio.h&amp;gt;&lt;/span>&lt;span style="color:#75715e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">inline&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">foo&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#ae81ff">42&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">main&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#66d9ef">int&lt;/span> n &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">foo&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#a6e22e">printf&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;%d&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>, n);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>并且, 你会发现, 在不同的优化等级, 其运行结果还不一样:&lt;/p></description></item><item><title>Atomic Variable Demo</title><link>https://riversjin.github.io/posts/atomic-variable-demo/</link><pubDate>Wed, 07 Dec 2022 22:50:55 +0800</pubDate><guid>https://riversjin.github.io/posts/atomic-variable-demo/</guid><description>&lt;p>接上一篇文章, 这一篇我们来用一些示例程序, 来探讨一下在不同平台下原子变量的行为.&lt;/p>
&lt;p>示例代码库我放在了 &lt;a href="https://github.com/RiversJin/AtomicVariableDemo">https://github.com/RiversJin/AtomicVariableDemo&lt;/a>
使用Rust实现(想顺便温习一下Rust的语法)&lt;/p>
&lt;p>项目结构很简单&lt;/p>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>abc@310a0ca1fb3d:~/workspace/t/src$ tree
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>├── bin
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── t1.rs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── t2.rs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── t3.rs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── t4.rs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ └── t5.rs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>└── main.rs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>1 directory, 6 files
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h1 id="计数器">计数器&lt;/h1>
&lt;p>首先是main.rs, 这里比较了两种计数器相加的方法, 一个是使用普通变量全局变量R_MUT, 另一个是使用原子变量R, 其中, 原子变量使用Relaxed的内存序约束.&lt;/p></description></item><item><title>浅析Rust的#[derive(Clone)]</title><link>https://riversjin.github.io/posts/rust-derive-clone/</link><pubDate>Thu, 13 Oct 2022 22:35:17 +0800</pubDate><guid>https://riversjin.github.io/posts/rust-derive-clone/</guid><description>&lt;p>在学习rust的模板的时候, 我遇到了一个奇怪的问题. 就是关于derive(Clone)这个派生宏的. 有点意思, 跟大家分享一下.&lt;/p>
&lt;h1 id="问题来由">问题来由&lt;/h1>
&lt;p>我们先来看这段代码:&lt;/p>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-rust" data-lang="rust">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">use&lt;/span> std::rc::Rc;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">trait&lt;/span> MayNotClone{}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#[derive(Clone)]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">CloneByPtr&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>T&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#66d9ef">where&lt;/span> T: &lt;span style="color:#a6e22e">MayNotClone&lt;/span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> item: &lt;span style="color:#a6e22e">Rc&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>T&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">trait&lt;/span> MustBeClone: Clone {}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">impl&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span>T&lt;span style="color:#f92672">&amp;gt;&lt;/span> MustBeClone &lt;span style="color:#66d9ef">for&lt;/span> CloneByPtr&lt;span style="color:#f92672">&amp;lt;&lt;/span>T&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#66d9ef">where&lt;/span> T:&lt;span style="color:#a6e22e">MayNotClone&lt;/span>{}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>代码本身很简单, 首先声明一个trait叫做MayNotClone, 它不一定满足Clone这个trait, 然后, 再声明一个名为MustBeClone的trait, 这个trait必须实现Clone. 到这里, 一切正常, 对吧?&lt;/p></description></item><item><title>Atomic Variable &amp; Memory Order</title><link>https://riversjin.github.io/posts/atomic-variable/</link><pubDate>Tue, 04 Oct 2022 21:26:37 +0800</pubDate><guid>https://riversjin.github.io/posts/atomic-variable/</guid><description>&lt;p>这一篇文章, 我们浅谈一下原子变量以及内存序模型. 有什么问题欢迎留言指出, 我们可以一起讨论.&lt;/p>
&lt;h1 id="atomic-variable">Atomic Variable&lt;/h1>
&lt;p>首先我们先来聊一下什么是&amp;quot;原子性&amp;quot;. 假如有这样一段代码&lt;/p>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">int&lt;/span> v;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">add&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v &lt;span style="color:#f92672">=&lt;/span> v &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>在执行add函数时, CPU需要先从内存中取出v的值, 然后计算+2, 最后写回到内存中. 如果只有一个执行序, 那当然无所谓. 但如果有并发呢? 那就比较麻烦了. 我们讨论最简单的情况, 即双线程并发执行一次这个函数.&lt;/p>
&lt;p>这就可能出现多种情况. 比如, 其中一个线程先执行成功, 然后另一个线程执行. 那么当二者都执行成功后. v的值变为4.&lt;/p>
&lt;p>或者, 它们一起开始执行. 线程1先读取到v的值, 开始计算+2, 但还没来得及写回; 而线程2已经开始运行, 开始读取v值, 为0, 开始计算+2. 最终, 无论这两个执行绪谁先执行完成, 都会只是向内存写入2. 而不是预期中的4. 就像下面这样&lt;/p>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-gdscript3" data-lang="gdscript3">&lt;span style="display:flex;">&lt;span> T0 T1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">┌──────────────┬───────────────┐&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> load v (&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>) &lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">│&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">├──────────────┼───────────────┤&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> load v (&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>) &lt;span style="color:#960050;background-color:#1e0010">│&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">├──────────────┼───────────────┤&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> add &lt;span style="color:#ae81ff">2&lt;/span> (&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>) &lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> add &lt;span style="color:#ae81ff">2&lt;/span> (&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>) &lt;span style="color:#960050;background-color:#1e0010">│&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">├──────────────┼───────────────┤&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> store v (&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>) &lt;span style="color:#960050;background-color:#1e0010">│&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">├──────────────┼───────────────┤&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> store v (&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>) &lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">│&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">└──────────────┴───────────────┘&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>从这段代码来说, 这个+2的操作, 显然就不是原子性的. 如果是&amp;quot;原子性&amp;quot;的操作, 那就该这三个步骤合并为一个步骤, 一下子完成. 像这样&lt;/p></description></item></channel></rss>