マルチコンポジットとマルチコアCPU、コンポジット空間

1306 ワード

まず、次のプログラムの実行結果を見て、何度も実行します.
package main

import (
	"fmt"
	"sync"
)

var num int64 = 0
var max = 10000
var wg sync.WaitGroup

func main() {
	wg.Add(2)
	go addNum()
	go addNum()
	wg.Wait()
	fmt.Printf("num=%d 
", num) } func addNum() { for i := 0; i < max; i++ { num++ } wg.Done() }

出力結果は一定値ではなく、「max」変数値未満の出力もあります.
なぜこんなことになったのか、次は一歩一歩分析します.
まずnum++のcpuレベルでの実行を理解します.それは原子操作ではありません.
次のようになります.
int x = num; x = x + 1; num= x; (ここでxはレジスタを表し、amountはメモリを表す)私たちはあなたが1つのcpuしかないと仮定します.つまり、実行自体は同時ではありませんが、2つの協程があります.
num=0協程1 int x=numとする.このときx=0、num=0がコヒーレント2に切り替わる点に注意すると、xはレジスタであり、各コヒーレントは独立しており、numは共有されており、1つしかないので、混同を避けるために、ここでxはx 1として別の変数int x 1=numを表す.このときx 1=0 num=0 x 1=x 1+1となる.このときx 1=1はさらにコモン1 x=x+1に切り替わる.num= x; このときx=1 num=1はさらにコモン2 num=x 1に切り替わる.覚えておいてください.x 1=1ですからnum=1の結果は2ではなく1です.なぜですか.切り替え中にxが格納したデータが汚れたデータであるため、amountは別のスレッドに更新されたが、xは更新されなかった.
各コヒーレンスには独自のコヒーレンス空間があり、変数iが以上の2つのコヒーレンスにそれぞれ1部あることを指す.各cupコアには独自のレジスタがあり、実行中の変数がキャッシュされ、各コアには多層Cacheがあります.この場合、汚れたデータが現れるのはおかしくありません.このプログラムを正しく実行させるには、原子指令を使用します.
https://www.usenix.org/conference/osdi10/ad-hoc-synchronization-considered-harmful
https://software.intel.com/en-us/blogs/2013/01/06/benign-data-races-what-could-possibly-go-wrong