C++ 循环缓冲区的线程安全实现
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9743605/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Thread safe implementation of circular buffer
提问by Alexey
Circular_buffer from boost library is not thread-safe. So I wrapped boost::circular_buffer object in a class as shown below. Mutual exclusion between the threads is achieved (I think) by using conditional variables, a mutex and a lock acquisition/release. Is this implementation thread safe?
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;
};
EditThis is now a template class, which accepts an object of any type (not just cv::Mat
object).
编辑这现在是一个模板类,它接受任何类型的对象(不仅仅是cv::Mat
对象)。
采纳答案by Yochai Timmer
Yes.
If you lock all the public methods with the same lock it will be threadsafe.
是的。
如果您使用相同的锁锁定所有公共方法,它将是线程安全的。
You could consider using read-write locks, which may have better performance if you have a lot of concurrent readers.
你可以考虑使用读写锁,如果你有很多并发读者,它可能会有更好的性能。
If you don't have a lot of readers, it will just add overhead, but may be worth checking the option and testing.
如果你没有很多读者,它只会增加开销,但可能值得检查选项和测试。
回答by Willem Hengeveld
i think it looks fine, except that there is some pointless copies of Mat made in send
. You don't need the new, you can directly push the argument of send
to your cb.
我认为它看起来不错,只是有一些用send
. 您不需要新的,您可以直接将 的参数推send
送到您的 cb。
回答by Emile Cormier
Your implementation is similar to the one shown by this blogger. You should read that blog to see if you missed anything in your implementation.
您的实现类似于此博主展示的实现。您应该阅读该博客,看看您是否遗漏了实施中的任何内容。
If your Mat
objects are expensive to create/copy, you should avoid continuously creating/copying/deleting them. Instead, you should have a pool (aka free list) of Mat objects that continually get recycledin some kind of pipeline architecture. I describe this type of architecture in this answerto a related question.
如果Mat
创建/复制对象的成本很高,则应避免连续创建/复制/删除它们。相反,您应该有一个池(又名空闲列表)的 Mat 对象,这些对象在某种管道架构中不断被回收。我在这个相关问题的回答中描述了这种类型的架构。
In that answer, I suggested using a blocking stack to implement the pool, but you could also use your blocking circular_buffer
. The reason I suggested a stack was because I thought it may be more cache-friendly, but I never actually measured to see if it would make a difference.
在那个答案中,我建议使用阻塞堆栈来实现池,但您也可以使用阻塞circular_buffer
。我建议堆栈的原因是因为我认为它可能对缓存更友好,但我从未实际测量过它是否会有所作为。
回答by Daniel Roethlisberger
Looks good at first glance, except that you are not using the buffer_not_full
condition at all. You probably want to add code similar to the buffer_not_empty
code.
乍一看看起来不错,只是您根本没有使用该buffer_not_full
条件。您可能希望添加与代码类似的buffer_not_empty
代码。