Потокобезопасная реализация кольцевого буфера - PullRequest
32 голосов
/ 16 марта 2012

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

#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).

Ответы [ 4 ]

16 голосов
/ 16 марта 2012

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

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

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

5 голосов
/ 17 марта 2012

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

2 голосов
/ 17 марта 2012

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

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

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

0 голосов
/ 16 марта 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...