Skip to content

fix(viz): dead lock when updating mask

Didier WECKMANN requested to merge fix-update-mask-deadlock into dev

Description

This fixes a possible deadlock when updating the mask: while you can, without deadlock, perform several read_lock on the same thread, having a write_lock, in another thread, in between two read_lock in the same thread, will trigger a deadlock between the write_lock and the second read_lock.

This small snippet demonstrates the problem, as "AFTER write_lock_1" and "AFTER read_lock_2" will never be displayed:

int main(int, char**)
{
  std::future<void> future;
    
  {
    std::cout << "START" << std::endl;
    sight::core::mt::read_write_mutex mutex;

    std::cout << "BEFORE read_lock_1" << std::endl;
    sight::core::mt::read_lock read_lock_1(mutex);
    std::cout << "AFTER read_lock_1" << std::endl;

    future = std::async(
        std::launch::async,
        [&mutex]()
    {
        std::cout << "BEFORE write_lock_1" << std::endl;
        sight::core::mt::write_lock write_lock_1(mutex);
        std::cout << "AFTER write_lock_1" << std::endl;

        std::this_thread::sleep_for(std::chrono::seconds(10));

        std::cout << "thread stopped" << std::endl;
    });

    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "BEFORE read_lock_2" << std::endl;
    sight::core::mt::read_lock read_lock_2(mutex);
    std::cout << "AFTER read_lock_2" << std::endl;
  }

  future.wait();

  std::cout << "EXIT_SUCCESS" << std::endl;
  return EXIT_SUCCESS;
}

In our code:

  • First read_lock is done in sight::module::viz::scene3d::adaptor::volume_render::update_mask() : 356 : const auto mask = m_mask.lock();
  • In between write_lock is done in sight::module::filter::image::image_extruder::add_reconstructions() : 114 : const auto image_out = m_extruded_image.lock();
  • Second read_lock, called from within sight::module::viz::scene3d::adaptor::volume_render::update_mask(), is done in sight::viz::scene3d::detail::resource_manager::load() : 210 : const sight::data::mt::locked_ptr lock(it->second.object.lock());

Results

  • This deadlock fixed, no new deadlock

How to test it?

This can be very hard to reproduce, but something like that may trigger the problem:

  • Launch sight_viewer
  • Load an image
  • Use the freehand crop

Otherwise, test with the application where this has been spotted. This may occur more frequently on Windows platform in Debug mode.

Merge request reports