当您使用 ThreadLocal<T> 并且T实现IDisposable时,应该如何处置ThreadLocal内部保留的成员?

根据ILSpy,ThreadLocal的Dispose()和Dispose(bool)方法是

public void Dispose()
{
    this.Dispose(true);
    GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
    int currentInstanceIndex = this.m_currentInstanceIndex;
    if (currentInstanceIndex > -1 && Interlocked.CompareExchange(ref this.m_currentInstanceIndex, -1, currentInstanceIndex) == currentInstanceIndex)
    {
        ThreadLocal<T>.s_availableIndices.Push(currentInstanceIndex);
    }
    this.m_holder = null;
}

似乎ThreadLocal不会尝试对其子成员调用Dispose。我不知道如何引用它内部分配的每个线程,所以我可以照顾它。

我用以下代码运行了一个测试,该类从未被丢弃
static class Sandbox
{
    static void Main()
    {
        ThreadLocal<TestClass> test = new ThreadLocal<TestClass>();
        test.Value = new TestClass();

        test.Dispose();
        Console.Read();
    }
}

class TestClass : IDisposable
{
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected void Dispose(bool Disposing)
    {
        Console.Write("I was disposed!");
    }
}

最佳答案

我查看了ThreadLocal<T>中的代码,以了解当前Dispose的功能,这似乎是很多巫毒教徒。显然处理线程相关的东西。

但是,如果T本身是一次性的,则不会处理这些值。

现在,我有一个解决方案-ThreadLocalDisposables<T>类,但是在给出完整定义之前,值得考虑一下如果编写以下代码会发生什么:

var tl = new ThreadLocalDisposables<IExpensiveDisposableResource>();
tl.Value = myEdr1;
tl.Value = myEdr2;
tl.Dispose();

应该同时处理myEdr1myEdr2吗?还是只是myEdr2?还是应该在分配myEdr1后处置myEdr2

我不清楚语义应该是什么。

但是对我来说很明显,如果我编写了以下代码:
var tl = new ThreadLocalDisposables<IExpensiveDisposableResource>(
    () => new ExpensiveDisposableResource());
tl.Value.DoSomething();
tl.Dispose();

然后,我希望应该处理工厂为每个线程创建的资源。

因此,我将不允许直接为ThreadLocalDisposables分配一次性值,而仅允许工厂构造函数。

这是ThreadLocalDisposables:
public class ThreadLocalDisposables<T> : IDisposable
    where T : IDisposable
{
    private ThreadLocal<T> _threadLocal = null;
    private ConcurrentBag<T> _values = new ConcurrentBag<T>();

    public ThreadLocalDisposables(Func<T> valueFactory)
    {
        _threadLocal = new ThreadLocal<T>(() =>
        {
            var value = valueFactory();
            _values.Add(value);
            return value;
        });
    }

    public void Dispose()
    {
        _threadLocal.Dispose();
        Array.ForEach(_values.ToArray(), t => t.Dispose());
    }

    public override string ToString()
    {
        return _threadLocal.ToString();
    }

    public bool IsValueCreated
    {
        get { return _threadLocal.IsValueCreated; }
    }

    public T Value
    {
        get { return _threadLocal.Value; }
    }
}

这有帮助吗?

关于c# - 处置ThreadLocal <IDisposable>中保存的元素的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7669666/

10-12 20:16