私はCygwin GCCを使用しており、次のコードを実行します。
#include <iostream>
#include <thread>
#include <vector>
using namespace std;
unsigned u = 0;
void foo()
{
u++;
}
int main()
{
vector<thread> threads;
for(int i = 0; i < 1000; i++) {
threads.push_back (thread (foo));
}
for (auto& t : threads) t.join();
cout << u << endl;
return 0;
}
次の行でコンパイルされますg++ -Wall -fexceptions -g -std=c++14 -c main.cpp -o main.o
。
1000を出力しますが、これは正しいです。ただし、以前にインクリメントされた値をスレッドが上書きするため、数は少なくなると予想していました。なぜこのコードは相互アクセスの影響を受けないのですか?
私のテストマシンには4つのコアがあり、私が知っているプログラムには制限を設けていません。
共有のコンテンツをfoo
もっと複雑なものに置き換えても問題は解決しません、例えば
if (u % 3 == 0) {
u += 4;
} else {
u -= 1;
}
while true; do res=$(./a.out); if [[ $res != 1000 ]]; then echo $res; break; fi; done;
ます。たとえば、私のシステムでは999や998が出力されます。
u
メモリに書き戻すとしましょう。CPUは実際には、メモリラインu
がCPUのキャッシュにないことに気づくなどの驚くべきことを行い、インクリメント操作を再開します。これが、x86から他のアーキテクチャーへの移行が目を見張るような体験になる理由です。