2. 前言:权 衡的艺术
Premature optimisation is the root of all evil
Donald Knuth
Intuition is frequently wrong—be data intensive
《 Real-World Concurrency 》 from ACM-Queue
尽量以最小的代价换取最大的收益,杜绝复杂性
3. 怎样优 化程序的并行部分?
“Multi-threading is easy. Correct synchronization is hard.”
按照优先程度从高到低:
逻辑层面:减少数据共享
编码层面:减少锁粒度
工具层面:使用轻量同步机制
7. 陷阱 :真的没有共享吗 ?
分析:多线程计数,分配一个 int 数组 result 作为结果集
线程启动时分配连续的 id
1 号线程更新 result[1] , 2 号线程更新 result[2] ,以此类推
需要取计数值时,取 result[] 之和
没有线程冲突?事实并非如此
01/13/14
8. 伪 共享 (False Sharing) :
原因: CPU load memory into cache by "line“
cat /proc/cpuinfo | grep cache_alignment (64 bytes)
9. 无处 不在的 False-Sharing
除了 Continuous Array :
The linker lay out global or static data closely in the memory
structs and C++ object layout is compact
Two individual objects on the heap happens to be nearby.(Especially
for same kind of objects allocated using its own memory-pool or slaballocator)
17. 到底要不要加锁 ?
基本数据类型—— CPU 自动保证的原子操作:
The Intel486 processor :
• Reading or writing a byte
• Reading or writing a word aligned on a 16-bit boundary
• Reading or writing a doubleword aligned on a 32-bit boundary
The Pentium processor (and newer processors since) :
• Reading or writing a quadword aligned on a 64-bit boundary
• 16-bit accesses to uncached memory locations that fit within a 32-bit
data bus
The P6 family processors (and newer processors since) :
• Unaligned 16-, 32-, and 64-bit accesses to cached memory that fit
within a cache
《 Intel 64 and IA-32 Architectures Software Developer's Manual 》 Volume 3
01/13/14
18. 有限的“原子”语义
原子语义:
如果 x = a ,另一个线程执行 x = b
其他线程在任何时候读到 x 的值,不会出现 a 或 b 之外的值
对 read-modify-write / read-check-modify 等无能为力
i++ , a = a + n
if (x == a ) x = b
不能保证对其他线程的可见性 (Visibility) :
编译器优化 & CPU 乱序执行,实际执行顺序与预期顺序不一致
CPU write-buffer ,使 CPU 对某块地址的修改不会立即反映到内存
寄存器优化, Memory Barrier 等等
(水很深,个人理解有限,不详细阐述)
01/13/14
19. Visibility 问题实 例(一)
实例:使用 bool 控制另一个线程中的循环 :
Thread 1:
while(A)
{
read(B) // 此时 B 不一定等于 some_value
// do something
}
Thread 2 :
B = some_value()
A = 1 //Tell Thread1 that B is ready
20. Visibility 问题实 例(二)
实例:使用 double-checked lock 实现 singleton 模式
class Foo {
static Foo* instance() {
if (m_pFoo == NULL) {
scoped_lock(m_mutex);
if (m_pFoo == NULL) {
m_pFoo = new Foo;
//m_pFoo 的写入可能会在初始化 Foo 之前执行,后果?
}
}
return m_pFoo;
}
// omitted for brevity ...
}
01/13/14
21. 题 外话 : C++ 线 程安全的 singleton 模
式
GCC 自动保证 thread-safe local statics initialization
-fno-threadsafe-statics 可以关闭该功能
class Foo{
public:
Foo* instance() {
static Foo instance;
r
}
// omitted for brevity
};
eturn &instance;
产生的汇编代码:
(objdump –d obj)