Golang C++11 中的原子操作对比

Posted by w@hidva.com on October 18, 2017

在学习 C++11 中新增的原子操作以及相应的 memory model 之后; 再看 golang 中的 sync/atomic, 可以发现 sync/atomic 提供的是纯粹的原子操作, 等同于 c++11 中的 std::memory_order_relaxed. 所以 The Go Memory Model 在介绍 golang memory model 并未提及到 atomic 可以实现同步语义. (这一点待确定!!!!

按我理解 C++11 中的原子操作自带各种同步语义是由于目前硬件限制决定的: CPU 在实现缓存机制时无法做到完全透明, 所以开发者在开发时不得不考虑 CPU 缓存所带来的各种副作用, 这由此导致了 C++11 的原子操作除了操作是原子的之外, 还自带了同步光环. 所以从长远来讲我觉得 golang 中的原子操作才是正宗的原子操作.

同样由于 golang 的原子操作没有同步光环, 导致无法实现各种无锁数据结构, 曾一度以为很是可惜. 后来意识到在 golang 中或许其实并不需要无锁数据结构, 主要是因为当一个 goroutine 被 block 之后, golang 会调度其他 goroutine 运行, 所以程序整体并没有 block. 另外大多数无锁数据结构都是基于 CAS 以及无脑循环重试实现, 如下:

typedef struct {
	int key;
	struct node *next;
} node;


typedef struct {
	node *head;
} list


void list_insert(list *l, int k) {
	node *n = new node(k);

	do {
		node *prev = MCASRead(&l->head);
		node *curr = MCASRead(&prev->next);

		while (curr->key < k) {
			prev = curr;
			curr = MCASRead(&curr->next);
		}

		n->next = curr;
	} while (!MCAS(1,&prev->next, curr, n));

	return ;
}

以上代码参考 Concurrent Programming Without Locks. 所以在 golang 中使用锁或许并发性能更好一点.

但是还是觉得有一点可惜啊, 毕竟这样就无法实现 leveldb 中那个仅需要写加锁, 读不需要加速的 skiplist 了.