Skip to content

(core): use RAII mechanism and weak_prt / shared_ptr pattern to protect fwData against race condition and memory dumping

What does this MR do?

Three class has been added: weak_ptr, locked_ptr, shared_ptr. Each of them will "store" the pointer to the real data, but in a different manner and with a different way to access it.

You will receive a weak_ptr when calling IServices::getWeak[Input|Inout|Output]() and a a locked_ptr when calling IServices::getLocked[Input|Inout|Output]()

weak_ptr will use a hidden std::weak_ptr to hold the real data, but it can only be accessed by "locking" it through a locked_ptr. locked_ptr will hold a std::shared_ptr, but also a mutex lock to guard against concurrent access and a buffer lock to prevent dumping on disk when the data holds an array object. RAII mechanism will ensure that everything is unlocked once the weak_ptr is destroyed. The underlying lock mutex will be a write mutex locker if the data is NOT const, a read mutex locker if the data is const. Using an Input will anyway force you to have const data, forcing you to use a read mutex locker. You can simply get the original data through a std::shared_ptr by calling locked_ptr::getShared()

Typically, in a service the code should look like:

{
  auto weakInput   = this->getWeakInput< ::fwData::Integer >(s_INPUT);
  auto sharedInput = weakInput.lock();

  // after that the data referenced by s_INPUT is "read locked"
  std::cout << sharedInput->getValue();
  ....
}

or, simpler:

{
  auto sharedInOut = this->getLockedInOut< ::fwData::Integer >(s_INOUT);

  // after that the data referenced by s_INOUT is "write locked"
  sharedInOut->setValue(666);
  ....
}

Since weak_ptr holds the data object as a std::weak_ptr without locks, you can use it to store the pointer in a class member, sparing the lookup at the input/inout/output maps (in starting() instead at each call of updating()) if , of course, the data object already exists at this time. You just have to call weak_ptr::lock() in updating(), so you will get the locked_ptr, allowing you to access the data object.

How to test it?

  • Launch fwServicesTest
  • Try to replace all IServices::get[Input|Inout|Output]() by IServices::getWeak[Input|Inout|Output]() or IServices::getLocked[Input|Inout|Output]() in a given service and test the service.

Associated Issues/Merge Requests

Edited by Didier WECKMANN

Merge request reports