Страницы

Поиск по вопросам

пятница, 9 ноября 2018 г.

в чем проблема с отсутствием мьютексов в коде?

здравствуйте, начинаю очередной раз разбираться с многопоточностью... нашел простой пример для наглядности рассинхронизации доступа, но не понимаю некоторых вещей:
struct Counter { int value;
Counter() : value(0){}
void increment(){ ++value; } };
int main() { Counter counter;
std::vector threads; for(int i = 0; i < 5; ++i){ threads.push_back(std::thread([&counter](){ for(int i = 0; i < 100; ++i){ counter.increment(); } })); }
for(auto& thread : threads){ thread.join(); }
std::cout << counter.value << std::endl;
return 0; }
совершенно не могу понять почему вылетают разные значения... у нас ведь join() т.е. мы ждем когда каждый из пяти потоков выполнится один за другим(т.е. инкрементирует по 100 раз каждый), я понимаю если б detach() стоял, то была бы жесть... а так каждый поток из пяти один за другим ведь следом идут... почему значения отличные от 500 получаются. либо я чего-то не учитываю... разве не верно, что в первом потоке будет 100, и в последующих будут на 100 больше?


Ответ

У Вас не синхронизирован доступ к counter, поэтому, в силу data races, как Вам уже правильно указал VladD, у Вас в коде UB. Чтобы исправить код, Вам нужно синхронизировать доступ к counter внутри, или снаружи. Можно сделать так:
struct Counter { std::atomic_int value; ... };
Или так:
std::mutex guard;
std::vector threads; for(int i = 0; i < 5; ++i) { threads.push_back(std::thread([&counter, &guard]() { for(int i = 0; i < 100; ++i) { std::lock_guard lock{guard}; counter.increment(); } })); }
Или ещё массой других вариантов — главное, чтобы пропали гонки(data races)

Комментариев нет:

Отправить комментарий