本文是对 Jeff Preshing 的 Double Checked Locking Is Fixed in C++ 11 笔记。
因为 synchronization 只需要在实例第一次创建时保证;此后( instance != nullptr
时)都不需要锁来保证 synchronization。
在第一次判断实例为空和上锁之间存在一个 potential race,因此上锁后需要再一次判断实例是否为空。
这也是 double checked 的来由。
所以一个传统但并不100%正确的 DCLP 实现如下:
1 | class Singleton { |
这基本是早起 C++ DCLP 的实现架子。
语句
1 | instance = new Singleton(); |
在 C++ 中实际上等效于
1 | tmp = operator new(sizeof(Singleton)); // step 1: allocate memory via operator new |
注意:其中除了分配内存是固定第一步之外,构造对象和赋值内存地址的生成代码顺序是由编译器自己决定。这里的顺序只是一种可能性。
近段有相当一部分时间在熟悉和练习 ASIO。
练习过程中发现 ASIO 中如何使用&管理 buffer 是新手大概率会遇到的问题。
结合最近几个 practice demo,稍微简单总结了一下使用经验:
0x00
const_buffer
和 mutable_buffer
是两个 fundamental buffer classes。二者的区别在语义上表达的很明显了。
实现上二者提供的接口非常一致,除了一个面向 const void*
,另一个面向 void*
。这点可以从 ctor 和 data()
中看出。
另外,为了和 C++ 现有的 const cast semantics 保持一致,一个 mutable_buffer
对象可以 implicitly converted to const_buffer
。
首先承认这个标题乍看之下很像 troll,但真的不是 troll;“避免使用”总的来说更接近 whenever possible 的意思。
另外,这篇 post 面向的主要是偏底层的、直接使用 system calls 或其 runtime wrapper(glibc)的开发者,最典型的比如 C/C++ 开发者。
其他语言的开发者通常因为要么 runtime “屏蔽”了这部分内容(如 Java);要么 runtime 自身对这部分做了较大的抽象/改造(如 Golang),因此很难对此 post 提到的各种观点/做法产生共鸣。
FYI:自从工作后中文写作能力一直在退化,因此这篇文章如果存在语句不通顺或者用词不当的地方,烦请见谅。
signal 源自 Unix,后来成为 POSIX 标准的一部分,现在则被几乎所有的 *nix 系统支持。
signal 本质上是一种通讯机制,用于系统在某个事件(event)发生时通知某个进程(或线程)。
其实是 Jeff Preshing 的 Acquire and Release Fences Don’t Work the Way You’d Expect 这篇文章的笔记。