Назад к вопросамЧто не так, если два потока одновременно выполняют
JuniorДебаггингОчень часто
Что не так, если два потока одновременно выполняют count_up?
int counter = 0;
void count_up() {
for (int i = 0; i < 100000; ++i) {
++counter;
}
}Гонка данных: запись в counter из двух потоков без синхронизации — неопределённое поведение
- Считать
++counterнеделимым: он читаетcounter, прибавляет единицу и записывает результат, а другой поток может вклиниться между этими шагами. - Ждать предсказуемой потери: гонка данных — неопределённое поведение, и стандарт не обещает никакого итога, даже числа меньше
200000.
- Почему запуск, напечатавший
200000, не доказывает, что программа верна? - Как
std::atomic<int>исправляет этот счётчик без мьютекса?
Исправление
++counter читает значение, прибавляет единицу и записывает результат, поэтому потоки должны выполнять его по очереди. Мьютекс, захваченный через std::lock_guard, пропускает к counter один поток за раз:
#include <mutex>
int counter = 0;
std::mutex m;
void count_up() {
for (int i = 0; i < 100000; ++i) {
std::lock_guard<std::mutex> guard(m);
++counter;
}
}Для одного счётчика подойдёт и атомарная переменная std::atomic<int> counter{0};: её ++ неделим, и мьютекс не нужен.