Подтвердить что ты не робот

Реализация потокового буферного буфера

Circular_buffer из библиотеки boost не является потокобезопасным. Поэтому я завернул boost:: circle_buffer в класс, как показано ниже. Взаимное исключение между потоками достигается (я думаю) с использованием условных переменных, мьютекса и фиксации/освобождения блокировки. Безопасна ли эта реализация?

#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/circular_buffer.hpp>

// Thread safe circular buffer 
template <typename T>
class circ_buffer : private boost::noncopyable
{
public:
    typedef boost::mutex::scoped_lock lock;
    circ_buffer() {}
    circ_buffer(int n) {cb.set_capacity(n);}
    void send (T imdata) {
        lock lk(monitor);
        cb.push_back(imdata);
        buffer_not_empty.notify_one();
    }
    T receive() {
        lock lk(monitor);
        while (cb.empty())
            buffer_not_empty.wait(lk);
        T imdata = cb.front();
        cb.pop_front();
        return imdata;
    }
    void clear() {
        lock lk(monitor);
        cb.clear();
    }
    int size() {
        lock lk(monitor);
        return cb.size();
    }
    void set_capacity(int capacity) {
        lock lk(monitor);
        cb.set_capacity(capacity);
    }
private:
    boost::condition buffer_not_empty;
    boost::mutex monitor;
    boost::circular_buffer<T> cb;
};

Изменить. Теперь это класс шаблона, который принимает объект любого типа (а не только объект cv::Mat).

4b9b3361

Ответ 1

Да.
Если вы заблокируете все общедоступные методы с помощью той же блокировки, это будет потокобезопасно.

Вы можете использовать блокировки чтения-записи, которые могут иметь лучшую производительность, если у вас много параллельных читателей.

Если у вас мало читателей, это просто добавит накладные расходы, но может стоить проверить опцию и тестирование.

Ответ 2

Я думаю, что это выглядит хорошо, за исключением того, что есть несколько бессмысленных копий Mat, сделанных в send. Вам не нужно новое, вы можете напрямую нажать аргумент send на свой cb.

Ответ 3

Ваша реализация аналогична реализации, описанной в этом blogger. Вы должны прочитать этот блог, чтобы узнать, пропустили ли вы что-либо в своей реализации.

Если ваши объекты Mat дороги для создания/копирования, вам следует избегать постоянного создания/копирования/удаления. Вместо этого у вас должен быть пул (aka free list) объектов Mat, который постоянно получает recycled в какой-то конвейерной архитектуре. Я описываю этот тип архитектуры в этом ответе на соответствующий вопрос.

В этом ответе я предложил использовать блокирующий стек для реализации пула, но вы также можете использовать блокировку circular_buffer. Причина, по которой я предложил стек, состояла в том, что я думал, что это может быть более безопасным для кэша, но я никогда не пытался понять, будет ли это иметь значение.

Ответ 4

Выглядит хорошо на первый взгляд, за исключением того, что вы вообще не используете условие buffer_not_full. Вероятно, вы захотите добавить код, похожий на код buffer_not_empty.