例子:求和 (再次出现)

分两个线程,计算 $1+1+1+\ldots+1$ (共计 $2n$ 个 $1$)

#define N 100000000
long sum = 0;

void Tsum() { for (int i = 0; i < N; i++) sum++; }

int main() {
  create(Tsum);
  create(Tsum);
  join();
  printf("sum = %ld\n", sum);
}

如果添加编译优化?

  • -O1: 100000000 😱😱
  • -O2: 200000000 😱😱😱

放弃 (2):程序的顺序执行假设

编译器对内存访问 “eventually consistent” 的处理导致共享内存作为线程同步工具的失效。

刚才的例子

  • -O1: R[eax] = sum; R[eax] += N; sum = R[eax]
  • -O2: sum += N;
  • (你的编译器也许是不同的结果)

另一个例子

while (!done);
// would be optimized to
if (!done) while (1);

保证执行顺序

回忆 “编译正确性”

  • C 状态和汇编状态机的 “可观测行为等价”
  • 方法 1:插入 “不可优化” 代码
    • asm volatile ("" ::: "memory");
      • “Clobbers memory”
  • 方法 2:标记变量 load/store 为不可优化
    • 使用 volatile 变量

extern int volatile done;

while (!done) ;