线程安全,无数据争用,无滞后的共享容器(circular_buffer)

时间:2016-01-29 10:25:12

标签: c++ multithreading c++11 thread-safety circular-buffer

我面临以下情况(我不得不承认我太不相信自己单独解决了问题。):我有线程A偶尔会创建新的cv :: Mat对象供线程B使用。我需要一个线程安全的容器C(在这种情况下是一个boost :: circular_buffer),它将保存线程A生成的cv :: Mat对象。然后,线程B需要不断迭代C中的所有项以生成动画。因此,我需要一个线程安全的C,这将禁止数据争用,但也不会导致(理想情况下)或非常小(如果不可能)延迟线程B的动画 - >当线程A更新C时,我想要线程B冻结。我能想到的最好的是:

#include <boost/circular_buffer.hpp>
#include <opencv2/core.hpp>
#include <boost/core/noncopyable.hpp>
#include <memory>
#include <type_traits>
#include <algorithm>

using im_buf = boost::circular_buffer<cv::Mat>;
class ImageBuffer : private boost::noncopyable { 
private:
  im_buf buffer;
  std::mutex mtx;
  std::unique_lock<std::mutex> lock;
public:
  // operator<< accepting cv::Mat, cv::Mat& and cv::Mat&&
  template <class T,
    class = typename std::enable_if
    <std::is_same<cv::Mat, typename std::decay<T>::type>
     ::value>::type>
   void operator<<(T&& mat) {
      lock.lock();
      buffer.push_back(std::forward<T>(mat));
      lock.unlock();
    }
    template <typename Func> // excpect callable objects only
    inline void iterate(Func func) {
      lock.lock();
      std::for_each(buffer.begin(),buffer.end(),func);
      lock.unlock();
    }
    inline ImageBuffer():
      buffer {settings::max_images_in_loop},
      mtx {},
      lock {mtx} {}
    ~ImageBuffer()=default;
    ImageBuffer(const ImageBuffer&&)=delete; 
    ImageBuffer& operator=(const ImageBuffer&&)=delete;  
};

(注意,即使这不是一个不变量,线程B也不会改变C或其任何内容(我喜欢在这里使用const_iterator但是boost :: circular_buffer不提供一个..)< / p>

然而,使用此代码线程B将在每次线程A添加新元素时冻结整个动画一段时间..所以, 一个。是不是有更好的方法? 湾实现真正的线程安全吗?

1 个答案:

答案 0 :(得分:2)

如果问题是动画,你就会担心错误的事情。互斥体对你的目的很好 - 不要担心拖延。

理想情况下,您需要以60fps的速度生成帧。根据您的应用,您可能只需20fps。直到数字电影问世,电影院才出现24fps。

60fps表示渲染帧时有16毫秒。在1GHz处理器上,这是1600万个时钟周期。为了避免由于其他进程导致的口吃,您需要使用不到一半的时间,比如说4-8百万个周期,因此50%到75%的处理器时间是空闲的,并且您只使用4-8毫秒的处理器时间来渲染帧。

等待其他线程,互斥锁或其他资源只会影响您的动画,如果它导致您错过下一帧的截止日期。

如果您的线程必须每隔几帧等待一次,由于互斥锁导致几万个时钟周期,这不会影响您的渲染,因为在下一帧显示之前您还有足够的时间屏幕。