I try to understand if I have a case where I need locking and at what place this is not thread-safe.
I have a relatively large buffer (say 300k elements). I have a producer who creates 1 datapoint each millisecond. On the other side I have a reader who starts at the newest value and then reads all new values every 10ms. But it just reads from the buffer, it does not pop. So the producer is expected to overwrite after 300k ms but due to the size of the buffer we do not expect to enter the readers position.
So my reduced example would be this:
int i = 0;
boost::circular_buffer<int> cb(1000);
// simulate producer is already running for some time
while(i < 50)
cb.push_back(i++);
std::jthread producer{[&i, &cb](){
while(true) {
cb.push_back(i++);
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}};
auto prev_last = cb.cend()-1;
while(true) {
// wait for buffer to fill
std::this_thread::sleep_for(std::chrono::milliseconds(10));
// get the last valid element
auto last_elem = cb.cend()-1;
// iterate from where we stopped last time
for(auto elem = prev_last; elem != last_elem; ++elem) {
fmt::print("read: {}n", *(elem));
}
// store end of this iteration
prev_last = last_elem;
}
more detailed example on godbolt
From what I read in the docs:
If multiple threads access a single circular_buffer, and at least one of the threads may potentially write, then the user is responsible for ensuring mutual exclusion between the threads during the container accesses.
it might not be thread-safe. But why?