vendredi 29 janvier 2016

thread-safe, data-race free, lag-free shared container (circular_buffer)

I face the following situation (which I have to admit I'm too noob to trust myself in solving alone..): I have thread A which occasionally creates new cv::Mat objects for thread B to consume. I need a thread-safe container C (a boost::circular_buffer in this case) which will hold the cv::Mat objects thread A generates. Then, thread B needs to constantly iterate through all items in C to produce an animation. Therefore I need a thread-safe C which will disallow data-races but also cause no (ideally) or very small (if not possible otherwise) lag to thread B's animation -> I dot want thread B to freeze when thread A updates C. The best I could come up with is this:

#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;  
};

(Note that even if this is not an invariant, thread B is not suppose to mutate C or any of its contents (I'd love to use a const_iterator here but boost::circular_buffer does not provide one..)

Yet, with this code thread B will freeze the entire animation for some time each time thread A adds new elements.. so, a. isn't there some better approach?? b. is implementation truly thread safe?

Aucun commentaire:

Enregistrer un commentaire