Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FeatureRequest] Fluent lifetime management #42

Closed
Wayofthesin opened this issue Jan 14, 2020 · 1 comment
Closed

[FeatureRequest] Fluent lifetime management #42

Wayofthesin opened this issue Jan 14, 2020 · 1 comment

Comments

@Wayofthesin
Copy link

Hi,

As far as I am concerned there are only 3 ways to manage the dependency lifetime. We could either specifically say there should be a single instance:

builder.registerType< MessageDispatcher >()
       .as< IMessageDispatcher >()
       .singleInstance();

or we could use single instance for child container living as long as long child container exist. The last way is default behaviour which I believe is one instance per resolve.

In our application we are concerned about very strong multi-threading. In such scenarios we might want:

  • One instance per thread
  • Multiple instances per thread
  • One instance across multiple threads

So the proposal is to add another syntax like:

builder.registerType< MessageDispatcher >()
       .as< IMessageDispatcher >()
       .withLifetimeManager(InstancePerThreadLifetimeManager());

InstancePerThreadLifetimeManager is an implementation of LifetimeManagerObject exposing the following methods:

  • resolveDependency
  • removeDependency

LifetimeManager has to have access to getOrCreateComponent method so it can make Hypodermic create new instances.

with std::thread::get_id we would be able to implement LifetimeManager so it distributes instances of requested object so there is always exactly one instance per thread. Such implementation injection allows us to fully customize the objects lifetime which is crucial for multi-threading project.

Thanks,
Patryk

@ybainier
Copy link
Owner

ybainier commented Jan 16, 2020

Hey,
why don't you create a nested container per thread? Everything you resolve in the nested container will have the lifetime of the thread. It is already available and pretty simple.

This will give (maybe again sorry) you a look at the resolution mechanism:

class ThreadLocal
{
public:
    ThreadLocal(shared_ptr< Container >& container,
                shared_ptr< TransientDependency > transientDependency,
                shared_ptr< SingleInstanceDependency > singleInstanceDependency)
    {
        ContainerBuilder builder;
        builder.registerType< UnknownSingleFromTopLevel >().singleInstance();
        
        auto nestedContainer = builder.buildNestedContainerFrom(*container);
        m_worker = nestedContainer->resolve< Worker >();
    }
};

class Worker
{
public:
    Worker(shared_ptr< TransientDependency > transientDep,
           shared_ptr< SingleInstanceDependency > singleInstanceDep,
           shared_ptr< NotThreadLocalSingleInstanceDep > notThreadLocalSingleInstanceDep,
           shared_ptr< UnknownToTopLevelSingleInstance > unknownToTopLevelSingleInstance);
};

now the configuration:

ContainerBuilder builder;
builder.registerType< SingleInstanceDependency >().singleInstance();
builder.registerType< NotThreadLocalSingleInstanceDep >().singleInstance();

auto container = builder.build();

for (auto i = 0; i < 8; ++i)
{
   thread([=]() { container->resolve< ThreadLocal >(); });
}
  • SingleInstanceDependency and NotThreadLocalSingleInstanceDep will always be shared accross all threads because they are configured inside the toplevel container; that's true even if it is resolved by the nested container.
  • Worker and TransientDependency are transient by default, that is, a fresh instance is created everytime they are resolved.
  • UnknownToTopLevelSingleInstance cannot be known from the top level container. This could be the trick you need.

So I guess you could split the configuration like so:

  • extend ContainerBuilder for the components of the whole app
  • extend ContainerBuilder for the components that are supposed to be thread local. That way, everytime you instantiate a thread, you can create a nested container with these merged capabilities.

Am I missing something or does this achieves your goal?

@ybainier ybainier closed this as not planned Won't fix, can't repro, duplicate, stale Jun 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants