(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]()
byIServices::getWeak[Input|Inout|Output]()
orIServices::getLocked[Input|Inout|Output]()
in a given service and test the service.
Associated Issues/Merge Requests
- Issues
- Closes #398 (closed)