Я не понимаю, почему это происходит. Возьмите следующий фрагмент кода псевдо:
volatile unsigned long count = 0;
volatile unsigned long sum = 0;
void ThreadFunction() {
InterlockedIncrement(&count);
InterlockedExchangeAdd(&sum, rand());
}
int main() {
for (int i = 0; i < 10; ++i) {
// This is the problematic instruction
InterlockedExchange(&count, 0);
InterlockedExchange(&sum, 0);
std::vector<boost::thread> threads(i);
for (int j = 0; j < i; ++j)
threads[j] = boost::thread(ThreadFunction);
while (count != i)
Sleep(0);
}
}
При самом первом запуске программы, когда i = 0
, атомный обмен на sum
из основного потока обычно происходит после завершенного порожденного потока. Операции на count
всегда выполняются в правильном порядке.
Это происходит только один раз; он выполняет операции в правильном порядке для оставшейся части цикла. Это не всегда происходит, но обычно происходит. Если я ворвусь в отладчик или перестану спать до атомарного добавления, инструкции будут выполнены в правильном порядке.
В любом случае, результатом является то, что значение, записанное потоком, заменяется на 0, которое должно было произойти еще до того, как поток был запущен.
Почему это происходит? Почему я не могу полагаться на процессор для выполнения атомарных инструкций, которые я дал ему в том порядке, в котором я их дал? Разве атомарная операция не подразумевает барьер памяти для предотвращения переупорядочения?
Примечание: это происходит в Visual Studio 2010. У меня нет других версий для тестирования.