Why does my boost::circular_buffer crash when accessed using an iterator?

In the following program, when I access elements from the front of the circular buffer using *(begin_iterator + index) I get a crash. But if I access the same elements using buffer[index], the crash is eliminated. (See the two commented lines below). Why does this happen?

#include <boost/circular_buffer.hpp> #include <thread> auto buffer = boost::circular_buffer<int>(5000); void f1() { const auto N = 500; while (true) { // Make sure the buffer is never empty if (buffer.size() < N+1) { continue; } auto front = buffer.begin(); volatile auto j = int{}; for (auto i = 0; i < N; ++i) { // j = *(front + i); // un-commenting this causes a crash // j = buffer[i]; // un-commenting this doesn't } buffer.erase_begin(N); } } void f2() { while (true) { // Make sure the buffer is at most half-full. if (buffer.size() > buffer.capacity() / 2) { continue; } static auto k = 0; buffer.push_back(k++); } } int main() { auto t1 = std::thread{f1}; auto t2 = std::thread{f2}; t1.join(); } 

1 Answer

You're experiencing undefined behavior because you're reading and modifying the same object unsynchronized from multiple threads.

Coding it one way or another might eliminate the crash, but the program is still wrong.

If we add a mutex, then there's no crash anymore:

#include <boost/circular_buffer.hpp> #include <thread> #include <mutex> boost::circular_buffer<int> buffer(5000); std::mutex mtx; void f1() { const auto N = 500; while (true) { std::lock_guard<std::mutex> lock(mtx); // Make sure the buffer is never empty if (buffer.size() < N + 1) { continue; } auto front = buffer.begin(); volatile auto j = int{}; for (auto i = 0; i < N; ++i) { j = *(front + i); // is OK now // j = buffer[i]; } buffer.erase_begin(N); } } void f2() { while (true) { std::lock_guard<std::mutex> lock(mtx); // Make sure the buffer is at most half-full. if (buffer.size() > buffer.capacity() / 2) { continue; } static auto k = 0; buffer.push_back(k++); } } int main() { auto t1 = std::thread{ f1 }; auto t2 = std::thread{ f2 }; t1.join(); } 
2

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like