2014-06-25 14 views
1

是否有內置的ThreadLocal<T>-like結構用於在每個唯一線程內共享對象,但是如果原始值已處置/銷燬/清除/清零,則重新創建它?ThreadLocal的新值<IDisposable> after .Value.Dispose()

這是我在實施與ConcurrentDictionary這種行爲(以下ThreadLocalDisposable2)的嘗試,但我希望只使用ThreadLocal<T>(如ThreadLocalDisposable1),但我不能讓Foo測試通過,.Values.Remove(this)不做我希望它會做的,還是引起ObjectDisposedException

public class Class1 
{ 
    [Test] 
    public void Foo() 
    { 
     using (var foo = ThreadLocalDisposable1.Get()) 
      foo.Foo(); 

     using (var foo = ThreadLocalDisposable1.Get()) 
      foo.Foo(); 
    } 

    [Test] 
    public void Bar() 
    { 
     using (var bar = ThreadLocalDisposable2.Get()) 
      bar.Foo(); 

     using (var bar = ThreadLocalDisposable2.Get()) 
      bar.Foo(); 
    } 
} 

[1]

public class ThreadLocalDisposable1 : IDisposable 
{ 
    private Stream _foo; 

    private static ThreadLocal<ThreadLocalDisposable1> _thread; 

    static ThreadLocalDisposable1() 
    { 
     _thread = new ThreadLocal<ThreadLocalDisposable1>(() => new ThreadLocalDisposable1(), true); 
    } 

    private ThreadLocalDisposable1() 
    { 
     _foo = new MemoryStream(); 
    } 

    public static ThreadLocalDisposable1 Get() 
    { 
     return _thread.Value; 
    } 

    public void Foo() 
    { 
     _foo.WriteByte(1); 
    } 

    public void Dispose() 
    { 
     //I do not think it means what I think it means 
     _thread.Values.Remove(this); 

     _foo.Dispose(); 
    } 
} 

[2]

public class ThreadLocalDisposable2 : IDisposable 
{ 
    private Stream _foo; 
    private int _thread; 

    private static ConcurrentDictionary<int, ThreadLocalDisposable2> _threads; 

    static ThreadLocalDisposable2() 
    { 
     _threads = new ConcurrentDictionary<int, ThreadLocalDisposable2>(); 
    } 

    private ThreadLocalDisposable2(int thread) 
    { 
     _thread = thread; 
     _foo = new MemoryStream(); 
    } 

    public static ThreadLocalDisposable2 Get() 
    { 
     return _threads.GetOrAdd(Thread.CurrentThread.ManagedThreadId, i => new ThreadLocalDisposable2(i)); 
    } 

    public void Foo() 
    { 
     _foo.WriteByte(1); 
    } 

    public void Dispose() 
    { 
     ThreadLocalDisposable2 thread; 
     _threads.TryRemove(_thread, out thread); 

     _foo.Dispose(); 
    } 
} 

編輯:

只是爲了澄清我的意思,基本上我希望所有的行爲ThreadLocal,但是當我打電話Dispose(該值,則ThreadLocalDisposable*在這個例子中基本Stream,而不是靜態ThreadLocal本身)採取處置實例退出流通領域,也就是說,如果呼籲再次 - 創建一個新的價值,如果它是一個品牌需要全新實例的新線程。

ThreadLocalDisposable1[1],是樣本類的東西,我認爲應該工作過,除了.Values.Remove(this)行不「把它拿出來流通的」,並強制一個新的實例爲線程創建。

ThreadLocalDisposable2[2],與ConcurrentDictionary,是一種方法,我實現替代的ThreadLocal與「退出流通」的行爲,我以後。

編輯:

這不是一個真實的使用情況下,我有,只是我能想到的一個普通例子,但如果你有例如靜態ThreadLocal<SqlConnection>或插座,並且它強行關閉(和其設置在最後的塊) - 丟棄連接實例,並透明地創建一個新的,如果再次調用。

+0

也許我沒有得到的想法,但你是否使用標記爲threadlocal的並行字典? – daryal

+0

@daryal不,我正在使用它,請參閱'ThreadLocalDisposable2'。我想使用'ThreadLocal',但是我無法完成它的工作,所以我有'ConcurrentDictionary',可以按我的需要工作,但感覺很亂。 –

+3

很難想象你在這裏要做什麼。不過,我建議你創建一個包含你想要拋棄的東西的類,並且創建一個該類的'ThreadLocal'實例。處理類中的處置/重新創建邏輯,而不是試圖管理'ThreadLocal'實例的字典。 –

回答

2

看起來你似乎比這要難得多。試想一下:

public class MyClass: IDisposable 
{ 
    private Stream _foo; 

    public MyClass Get() 
    { 
     if (_foo == null) 
     { 
      _foo = new MemoryStream(); 
     } 
    } 

    public void Foo() 
    { 
     _foo.WriteByte(1); 
    } 

    public void Dispose() 
    { 
     if (_foo != null) 
     { 
      _foo.Dispose(); 
      _foo = null; 
     } 
    } 
} 

現在,您可以創建這些之一:

ThreadLocal<MyClass> MyThing = new ThreadLocal<MyClass>(); 

,你可以寫:

using (MyThing.Value.Get()) 
{ 
    // do stuff 
} 

這似乎功能上等同於你想要做什麼與你的ConcurrentDictionary的東西。

這就是說,好像這是一件會得到更好的管理的另一種方式。我不知道你的應用程序,所以我不能肯定地說,但有一個像StreamSqlConnection這樣的有狀態對象作爲全局變量似乎是個不錯的主意。通常這些事情是針對特定工作而不是線程特定的,因此應該在開始作業時作爲參數傳遞。

+0

有意思......用非靜態的懶惰「單身人士」帶出ThreadLocal ......我沒有想過那樣。這並不理想,因爲它暴露了所有的System.Threading內部,而不是對調用者完全透明。我會給它一個去看看我能否支持它,謝謝。 –

+0

我是否正確理解它並不真正處理'MyClass',只是將'Stream'換掉,所以雖然它在這個簡化的例子中起作用,當MyClass具有其他數據時,例如,一個寫入流的實例字段而不是1,它會導致未指定的行爲。所以......我會說它在功能上並不等同於'ConcurrentDictionary'的東西。 –

+1

@IlyaKozhevnikov:不,它不會處理'MyClass'實例。這是我的觀點:創建一個持久對象來包裝一次性東西。 –