#1 2014-12-12 18:21:11

Alexis
Member
Registered: 2014-12-12
Posts: 4

Management of shared objects.

Hello Sascha:

I'm developing a File Manager for the MoonLight Desktop Environment it must be extended with different Views and Models in order to allow the navigation over different protocols (smb, ftp, davfs, etc). In order to allow this I use an approach similar to the SpellChecking example but instead of dictionaries I create object factories. But when a "Factory" module is unloaded the pointers to the created objects become into dangling pointers causing a total crash.

I was considering the creation of a registry of shared_ptr in each Factory in order to track then but I would like know if there is another way.

Cheers

Offline

#2 2014-12-15 03:47:08

sascha
Administrator
Registered: 2012-05-04
Posts: 46

Re: Management of shared objects.

Hi,

If I understood your scenario correctly, your service objects act as factories and create new objects on demand. Users of these created objects would need to track the life-time of the module providing the service object to avoid accessing code via the created object which has already been un-loaded.

A common solution I know of would be to re-design the system to not rely on services acting as object factories but instead let the consuming party instantiate self-defined objects or objects which are defined in dependent modules and which rely on functionality provided by one or more service objects. The required service objects are wrapped in a helper class which tracks the life-time of the service and which can be implemented in the same module which provides the service interface(s):

struct IFileProtocol
{
  virtual ~IFileProtocol() {}
  virtual void Foo() = 0;
};

class FileProtocolHandler : public IFileProtocol
{
private:

  us::ServiceTracker<IFileProtocol> m_FileProtocolTracker;

public:

  FileProtocolHandler(us::ModuleContext* context, /* service props if needed */)
   : m_FileProtocolTracker(context)
  {
    m_FileProtocolTracker.Open();
  }

  // IFileProtocol interface
  void Foo()
  {
    if(IFileProtocol* fileProto = m_FileProtocolTracker.GetService())
    {
      return fileProto->Foo();
    }
    else
    {
      // fallback / warning msg / etc
    }
  }
};

The intenral tracker takes care of listening to the appropriate service life-cycle events and returns NULL if the service has been withdrawn. If there is still need for a "object factory service", you may consider using the prototype scope feature. Instances returned by a PrototypeServiceFactory which are supposed to be long-living objects still need to be "monitored", which could be achieved by a helper class similar to the one above which again uses a service tracker to be notified when the service was unregistered (which happens on module unloading):

struct IView
{
  virtual ~IView() {}
  virtual void Foo() = 0;
}

class ViewHandler : public IView, private ServiceTracker<IView>
{
private:

  IView* m_View;

  // overwritten from ServiceTracker
  virtual void RemovedService(const ServiceRefereneType& ref, TrackedType service)
  {
    m_View = NULL;
    ServiceTracker::RemovedService(ref, service);
  }

public:

  ViewHandler(us::ModuleContext* context, const us::ServiceReference<IView>& ref)
   : ServiceTracker(context, ref)
   , m_View(context->GetService(ref))
  {
    this->Open();
  }

  // IView interface
  void Foo()
  {
    if (m_View)
    {
      return m_View->Foo();
    }
    else
    {
      // fallback / error msg / etc
    }
  }
};

- Sascha

Offline

#3 2014-12-15 22:43:48

Alexis
Member
Registered: 2014-12-12
Posts: 4

Re: Management of shared objects.

I was checking the  PrototypeServiceFactory documentation and I found that it makes a cache of the object service per module. This means that i can't get different service objects for the same module?

Cheers

Last edited by Alexis (2014-12-15 22:47:42)

Offline

#4 2014-12-15 22:56:03

sascha
Administrator
Registered: 2012-05-04
Posts: 46

Re: Management of shared objects.

The PrototypeServiceFactory::GetService() documentation reads

  The framework invokes this method for each caller requesting a service object using ServiceObjects::GetService().

So every call to ServiceObjects::GetService() will create a new instance (if the factory actually creates a new one). If you would use the ServiceFactory class instead (when registering a service), every module would get a different instance, but GetService() calls from the same module will return a cached instance.

Offline

#5 2014-12-15 23:01:11

Alexis
Member
Registered: 2014-12-12
Posts: 4

Re: Management of shared objects.

So as long as I register my Factory services as  PrototypeServiceFactory and use ServiceObjects::GetService()  from clients I will get different objects.

Thanks a lot!

Offline

#6 2014-12-15 23:11:19

sascha
Administrator
Registered: 2012-05-04
Posts: 46

Re: Management of shared objects.

Correct! ServiceObjects::GetService() can be used for all service scopes (singleton, module, and prototype) and will do the "right thing" (using ModuleContext::GetService() with a PrototypeScope will "downgrade" the scope to "module"). But you can also query the service scope of a ServiceReference<> object by looking at its SERVICE_SCOPE property.

Let me know if you run into more issues!

- Sascha

Offline

Board footer

Powered by FluxBB