为什么使用迭代器访问时 boost::circular_buffer 会崩溃?

问题描述

在下面的程序中,当我使用 *(begin_iterator + index) 从循环缓冲区的前端访问元素时,我崩溃了。但是,如果我使用 buffer[index] 访问相同的元素,则不会发生崩溃。 (请参阅下面的两条注释行)。为什么会发生这种情况?

#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();
}

解决方法

您遇到 undefined behavior 是因为您正在读取和修改多个线程不同步的同一个对象。

以一种或另一种方式编码可能会消除崩溃,但程序仍然是错误的。

如果我们添加一个互斥锁,那么就不会再有崩溃了:

#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();
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...