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?
lockmember variable should actually be a local variable in each function. If you do that you also don't need to unlock explicitly, it happens when the scope is left. Have a look at the usage examples forstd::unique_lockandstd::lock_guard.std::mutex mtx;without#include <mutex>"?