Here is the code:
std::vector<bool> a(req_count_);
std::vector<std::future<void>> waits(req_count_);
for (int i = 0; i < req_count_; i++) {
// send into a threadpool implementation
waits[i] = framework::Async([i, &a] {
a[i] = true; // write true
});
}
for (int i = 0; i < req_count_; i++) {
waits[i].wait(); // memory barrier?
}
int last_req_count = req_count_;
req_count_ = 0;
for (int i = 0; i < last_req_count; i++) {
if (!a[i]) { // read false
return false;
}
}
My question is does std::future::wait
serves as a memory barrier? std::future::wait
waits for the function call to complete, but does the function happens before std::future::wait
(e.g., does the state mutation caused by the function call visible from other threads)?
If std::future::wait
does not serves as a memory barrier, how can we implement the threadpool so that a memory barrier is triggered automatically when the future completes?
Please correct me if you think my understanding of memory barrier is wrong.
[container.requirements.dataraces]/2 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.[container.requirements.dataraces]/3 [ Note: For a
vector<int> x
with a size greater than one,x[1] = 5
and*x.begin() = 10
can be executed concurrently without a data race, butx[0] = 5
and*x.begin() = 10
executed concurrently may result in a data race. As an exception to the general rule, for avector<bool> y
,y[0] = true
may race withy[1] = true
. —end note ]
Emphasis mine. The race happens in a[i] = true;
. vector<bool>
is not a real container, accessing an "element" requires bit manipulations that touch neighboring elements.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With