To get by without a lock you should use a std::vector<atomic_flag_wrapper>
where atomic_flag_wrapper
wraps a std::atomic_flag
similar to the code in this answer.
With std::vector<bool>
you must use a lock, the standard explicitly tells you so:
Notwithstanding [res.on.data.races], implementations are required to avoid data races when the contents of the contained object in different elements in the same container, excepting vector<bool>
, are modified concurrently.
http://eel.is/c++draft/container.requirements.dataraces#2 (C++ draft, 02.08.2020), emphasis mine
In plain English:
std::vector<bool>
does not need to make sure that writes to two different elements are race-free; therefore there can be a data race; therefore you need a lock.
If it were e.g. a std::vector<char>
, then the standard makes sure that charVector[0]
and charVector[1]
can be written to concurrently. But still then you cannot write to charVector[0]
from more than one thread concurrently; you need to use atomics.
std:atomic<bool>
is not guaranteed to be lock-free, so you should use std::atomic_flag
which has this guarantee. You cannot put these into a std::vector
, though, because they are not copy constructible. For that, you need a wrapper as described in this answer.