0

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?

4
  • 2
    Your lock member 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 for std::unique_lock and std::lock_guard. Commented Jan 29, 2016 at 10:39
  • you could check the std::unique_lock::owns_lock to see if the mutex is locked. In case the mutex is locked B continue its process. If the mutex is not locked B iterate through all items to produce the animation. Commented Jan 29, 2016 at 10:47
  • you're not getting an error for std::mutex mtx; without #include <mutex>"? Commented Jan 29, 2016 at 11:03
  • no, weird - it might be implicitly included in some other header Commented Jan 29, 2016 at 11:19

1 Answer 1

2

If you problem is animation, you are worrying about the wrong thing. Mutexes are fine for your purpose - don't worry about stalling.

Ideally you need to produce frames at 60fps. You may get away with as little as 20fps depending on your application. Until the advent of digital cinema, cinemas only showed 24fps.

60fps means you have 16 milliseconds to render the frame. On a 1GHz processor that's 16 million clock cycles. To avoid stuttering due to other processes, you need to use less than half of that, say 4-8 million cycles, so 50% to 75% of processor time is idle, and you use only 4-8 milliseconds of processor time rendering the frame.

Waiting for other threads, mutexes or other resources only affects your animation if it causes you to miss the deadline for the next frame.

If your thread has to wait once every few frames, for a few tens of thousand clock cycles due to a mutex, this will not affect your rendering because you still have plenty of time before the next frame is due to be shown on the screen.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.