PerThreadLifetimeManager Dispose of registrations

Mar 12, 2014 at 5:54 PM
I have a windows service that reads a queue and for each item in the queue it gets the current command and creates a task to run it.

The problem is that to do so I use some registrations with the Per Thread Lifetime Manager, this way for example the DbContext doesn't raise any errors.

but when the task completes, the thread returns to the threadPool, and all of the registrations per thread stays in memory.

All I want is to dispose the registrations after the task is executed.


To to so I created a new PerThreadLifetimeManager that doesn't use the [ThreadStatic] because once you're not in the thread you can't access the property anymore
public class PerThreadLifetimeManager : LifetimeManager
    {
        protected static Dictionary<int, Dictionary<Guid,object>> values;
        protected readonly Guid key;

        public PerThreadLifetimeManager()
        {
            this.key = Guid.NewGuid();
        }
        public override object GetValue()
        {
            PerThreadLifetimeManager.EnsureValues();
            if (values.ContainsKey(System.Threading.Thread.CurrentThread.ManagedThreadId))
            {
                Dictionary<Guid, object> result;
                PerThreadLifetimeManager.values.TryGetValue(System.Threading.Thread.CurrentThread.ManagedThreadId, out result);
                if (result.ContainsKey(key))
                {
                    return result[key];
                }
            }
            return null;
        }

        public override void SetValue(object newValue)
        {
            PerThreadLifetimeManager.EnsureValues();

            if (!values.ContainsKey(System.Threading.Thread.CurrentThread.ManagedThreadId) || values[System.Threading.Thread.CurrentThread.ManagedThreadId] == null)
            {
                PerThreadLifetimeManager.values[System.Threading.Thread.CurrentThread.ManagedThreadId] = new Dictionary<Guid, object>();
            }

            if (values.ContainsKey(System.Threading.Thread.CurrentThread.ManagedThreadId) && values[System.Threading.Thread.CurrentThread.ManagedThreadId] != null)
            {
                var dic = PerThreadLifetimeManager.values[System.Threading.Thread.CurrentThread.ManagedThreadId];
                dic[key] = newValue;
            }
        }

        public override void RemoveValue()
        {
        }
        private static void EnsureValues()
        {
            if (PerThreadLifetimeManager.values == null)
            {
                PerThreadLifetimeManager.values = new Dictionary<int, Dictionary<Guid,object>>();
            }
            if (!values.ContainsKey(System.Threading.Thread.CurrentThread.ManagedThreadId))
            {
                values[System.Threading.Thread.CurrentThread.ManagedThreadId] = new Dictionary<Guid, object>();
            }
        }

        public static void ClearValues()
        {
            foreach (var item in values.SelectMany(x=>x.Value))
            {
                var disp = item.Value as IDisposable;
                if (disp != null)
                {
                    disp.Dispose();
                }
            }
            values = null;
        }
    }
And to dispose I created an Extension to the container
    public class PerThreadDisposeExtension : Microsoft.Practices.Unity.UnityContainerExtension,IDisposable
    {
        protected override void Initialize()
        {
            
        }

        public void Dispose()
        {
            PerThreadLifetimeManager.ClearValues();
        }
    }
Is that a better way to do this?
Mar 14, 2014 at 5:41 AM
An alternative approach would be to register with a HierarchicalLifetimeManager and then use a child container per thread. When the child container is disposed it will dispose all IDisposable objects registered with a HierarchicalLifetimeManager.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Mar 14, 2014 at 2:39 PM
Do you have an example of this?

with this lifetime manager that I created I reduced from 2.5Gb to 150Mb in memory of my service.
Mar 15, 2014 at 6:30 AM
I don't have a specific example but you can find the approach in the Unity source or some open source projects (Unity.MVC comes to mind). The approach is to register thread/request specific types with HierarchicalLifetimeManager. Then in the composition root call CreateChildContainer() and use that child container for resolving and when the thread/request is done Dispose the child container to clean up.

I'm also not saying that the child container approach is better but it is the other approach I've seen taken in these cases.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Jun 12, 2014 at 12:47 PM
Can you provide an example of how you implemented the PerThreadDisposeExtension? I get the concept but am having trouble getting it to dispose at the appropriate time.

Thanks in advance!
Jun 13, 2014 at 1:51 AM
My complete code is in the first topic, what's happening to you?
Jun 16, 2014 at 1:11 PM
I have used your code example and registered the extension with the container "unityContainer.AddNewExtension<PerThreadDisposeExtension >();" but the Dispose() never seems to be called. This means that instead of getting a new object when the thread is reused from the thread pool, I am getting the object that was originally registered with it. Is there something I need to do make sure that the Extension Dispose() method is called after the Task is complete?
Jun 16, 2014 at 4:32 PM
Is this a windows service?

What I do is this. I have an infinite loop for the service, and in this Loop I create the container on each loop, this way the old container is disposed at the end of the loop.
Jun 16, 2014 at 6:05 PM
Yes it is a windows service, but I see the difference now. I create a single Unity container at start-up of the service as opposed to creating a new one per loop as you are - that's why my dispose is not getting called, I only dispose of the container when the service is stopped.

Since I am using the Task library, what I managed to get to work (although not via configuration only as I would have preferred) is add a final "ContinueWith" method call that calls a new static method on the manager with my worker object's the thread id:
workerInfo.MyTask = new Task(() => StartWorker(workerInfo), agentWorkersCTS.Token);
workerInfo.MyTask.ContinueWith(t => WorkerPostProcess(workerInfo))
      .ContinueWith(t => PerThreadLifetimeManager.ClearThreadObjectValues(workerInfo.MyThread.ManagedThreadId));
This method simply removes that thread ID key from the values dictionary to remove the objects so that Unity will construct new objects the next time the thread is used from the ThreadPool.
 public static void ClearThreadObjectValues(int threadId)
 {
     if (values[threadId] == null)
         return;

      values.Remove(threadId);
}