线程安全执行循环缓冲区

时间:2012-03-16 19:48:12

标签: c++ multithreading boost opencv

boost库中的Circular_buffer不是线程安全的。所以我将boost :: circular_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对象)。

5 个答案:

答案 0 :(得分:16)

是。
如果使用相同的锁锁定所有公共方法,则它将是线程安全的。

您可以考虑使用 read-write locks ,如果您有很多并发读者,可能会有更好的效果。

如果你没有很多读者,它只会增加开销,但可能值得检查选项和测试。

答案 1 :(得分:5)

我觉得它看起来不错,只是在send中有一些毫无意义的Mat副本。您不需要新的,可以直接将send的参数推送到您的cb。

答案 2 :(得分:2)

您的实施类似于此blogger所示的实施方式。您应该阅读该博客,看看您是否遗漏了实施中的任何内容。

如果创建/复制Mat对象的代价很​​高,则应避免不断创建/复制/删除它们。相反,你应该有一个Mat对象的池(也就是自由列表),它在某种管道架构中不断得到回收。我在此answer中将此类架构描述为相关问题。

在该答案中,我建议使用阻塞堆栈来实现池,但您也可以使用阻塞circular_buffer。我建议堆栈的原因是因为我认为它可能对缓存更友好,但我从未真正测量过它是否会产生影响。

答案 3 :(得分:0)

乍一看看起来很不错,除了你根本没有使用buffer_not_full条件。您可能希望添加类似于buffer_not_empty代码的代码。

答案 4 :(得分:0)

很老的问题了:) 以下是采用无锁实现的Link

这里是此Link的BSD-2库。