MSVC 对多继承下的 EBO 支持的一个 workaround

首先简单介绍一下 EBO(Empty Base Class Optimization)。

因为 C++ 规定,任何一个 instance 在内存中必须要有唯一的地址,因此一个空的 class/struct 会在编译时被偷偷插入一个外人看不到的 char mem;,于是这个空类的每一个 instance 都可以有一个唯一的地址了。

但是如果将这个空类作为某个类的成员时,这个隐藏的成员会被计入内存布局之中,考虑到 memory padding,有时候会导致类对象体积膨涨一倍。

例如考虑:

1
2
3
4
5
6
7
8
9
class E {};

class A1 {
E e;
int i;
};

assert(sizeof(E) == 1);
assert(sizeof(A1) == 8);

我们会发现每一个 A1 的 instance 都占了 8-byte,比起 4-byte 足足翻了一倍。

占用内存无端变大导致 cache 问题啥的就不讲了,这方面的内容任何讲 computer architecture 的书应该都会有。

Read More

Chromium Base MessageLoop Internals (0)

Our fancy star in this post is class base::MessageLoopCurrent.

MessageLoopCurrent

Version: r70_3538
File: base/message_loop/message_loop_current.{h, cc}

MessageLoopCurernt is a proxy class for interactions with the MessageLoop bound to the current thread.

It is introduced to avoid direct uses of MessageLoop::current(), quoting from original comments:

Why: Historically MessageLoop::current() gave access to the full MessageLoop API, preventing both addition of powerful owner-only APIs as well as making it harder to remove callers of deprecated APIs (that need to stick around for a few owner-only use cases and re-accrue callers after cleanup per remaining publicly available).

Because it is a light-weight proxy, it contains only a single pointer to the MessageLoop bound to the current thread.

Read More

Monthly Read Posts in Oct 2018

Concurrency

C11 Lock-free Stack

使用C 11 atomic operations 实现一个轻量的 lock-free stack

  • pre-allocation,不需要考虑单个节点的销毁问题,所以不需要使用 hazard pointer
  • free 和 head 两个列表,两个单独的 head 均可用做 sentinel
  • 使用 aba counter 来避免 ABA problem

MySQL/InnoDB中,乐观锁、悲观锁、共享锁、排它锁、行锁、表锁、死锁概念的理解

感觉这篇讲的好混乱,几个概念是明显正交的都混在一起了。

瞄了一眼,基本脑子里都在找平常 locking mechanism 里的概念做映射了。


The method to epoll’s madness

总体写的一般,而且内容有点乱。

madness 应该指的就是 epoll 对外表现的是引用 file descriptor 但是内部维护的确实 file descrption。

Read More

Non-blocking Connect(2) and Error Handling

这是我在实现 ezio connector 时遇到的一个比较有意(keng)思(die)的问题。

在使用 non-blocking 的 connect(2) 时,按照 manual 的说法,如果调用的返回被认为是合理的(例如 EINPROGRESS),那么就需要:

Read More

Naming a Native Thread

这里所说的 naming 主要是为了能够被 debugger 识别,所以单纯的通过 TLS 存储一个额外的字符串是不够的。

Windows

Windows 上的做法有两种。

第一种是利用现成的 API SetThreadDescription()

通过这个 API 设置的名字据说新版的 minidump 和 WinDBG 都能认了。

不过缺点是这个 API 很新,从 Windows 10 1607 (build 14393) 开始才有,所以稳妥的使用方式还是从 kernel32.dll 里动态获取。

第二种做法比较传统,而且很不直观,来源是 MSDN 的一篇 doc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const DWORD kVCThreadNameException = 0x406D1388;

typedef struct tagTHREADNAME_INFO {
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;

void SetThreadName()
{
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = "Worker-Traditional";
info.dwThreadID = -1;
info.dwFlags = 0;

__try {
RaiseException(kVCThreadNameException, 0, sizeof(info) / sizeof(DWORD),
reinterpret_cast<ULONG_PTR*>(&info));
} __except(EXCEPTION_EXECUTE_HANDLER) {
}
}

基本上照搬 doc 上的代码就好了。

Read More

Using Boolean Switch with Python Argparser the Right Way

The Context

之前拿 Python 写了一个 CMake 的 build driver,因为要控制一些编译参数,所以使用了如下代码:

Read More

Monthly Read Posts in Sep 2018

Programming Language

Strong types for strong interfaces

How to add a type wrapper for built-in types.

Besides using phantom template parameter to avoid alias, one can also use private inheritance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class NamedType
{
public:
explicit NamedType(T const& value) : value_(value) {}
explicit NamedType(T&& value) : value_(std::move(value)) {}
T& get() { return value_; }
T const& get() const {return value_; }
private:
T value_;
};

class Width : NamedType<int> {
public:
using NamedType::NamedType;
using NamedType::get;
};

Passing strong types by reference – First attempt

This post is the sequal of the above post.

The main problem the post tryies to solve is: how to make copy of NamedType values cheap.

However, I am conservative on using reference-wrapper as the solution, because doing this has to expose the lifetime of the wrapped object to public; after all, reference-wrapper is only a point per se.

Read More