2009-05-28 12 views
7

我寫了一個特殊的數據結構,將在.NET庫中可用,並且此數據結構的功能之一是將是線程安全的,前提是隻有一個線程向其寫入數據,並且只有一個線程讀取來自它的數據(讀者線程和寫入器線程可以不同)。如何在.NET中檢測交叉線程訪問(強制執行線程關聯)?

問題是我該如何強制所有的讀操作都是由同一個線程執行的?

我的解決方案是捕獲System.Threading.Thread.ManagedThreadID,並在第一次讀取時將其存儲在私有成員中。然後,在隨後的讀取中檢查ManagedThreadID是否與保存的一致,以及它們是否與拋出異常不同。

這是否足夠,或者是否有不同的更可靠的機制來做到這一點。

注:有這個庫是沒有Windows.Forms的背景下使用的要求..

回答

6

當我遇到這種情況時,我使用了一個名爲ThreadAffinity的類。它的全部目的是記錄當前線程並拋出來自不同線程的無效訪問。您必須手動執行檢查,但它會爲您封裝少量工作。

class Foo { 
    ThreadAffinity affinity = new ThreadAffinity(); 

    public string SomeProperty { 
    get { affinity.Check(); return "Somevalue"; } 
    } 
} 

[Immutable] 
public sealed class ThreadAffinity 
{ 
    private readonly int m_threadId; 

    public ThreadAffinity() 
    { 
     m_threadId = Thread.CurrentThread.ManagedThreadId; 
    } 

    public void Check() 
    { 
     if (Thread.CurrentThread.ManagedThreadId != m_threadId) 
     { 
      var msg = String.Format(
       "Call to class with affinity to thread {0} detected from thread {1}.", 
       m_threadId, 
       Thread.CurrentThread.ManagedThreadId); 
      throw new InvalidOperationException(msg); 
     } 
    } 
} 

博客文章的主題:

1

你能不能要求讀取和寫入方法將線程或線程ID?然後,您可以僅將其與首先調用它的那個進行比較,如果它不匹配,則拋出異常或返回錯誤代碼,或者忽略該請求。

否則,你的建議也應該工作。您只需要比較線程ID。

+0

我不想依靠的讀/寫方法調用者什麼提供作爲輸入。否則,如果我可以可靠地使用ManagedThreadID方法,我想我會使用它。謝謝。 – 2009-05-28 17:46:14

1

而不是比較線程ID,你應該在建設過程中將ambient Thread存儲在你的班級。

class SingleThreadedClass 
{ 
    private Thread ownerThread; 

    public SingleThreadedClass() 
    { 
     this.ownerThread = Thread.CurrentThread; 
    } 

    public void Read(...) 
    { 
     if (Thread.CurrentThread != this.ownerThread) 
      throw new InvalidOperationException(); 
    } 

    public void TakeOwnership() 
    { 
     this.ownerThread = Thread.CurrentThread; 
    } 
} 
+0

爲什麼我應該使用對線程的引用而不是線程ID有任何特定的原因嗎?你的技術與我的技術非常相似,除了它使用對線程的引用而不是ID。只是好奇.. – 2009-05-28 17:53:04

+0

我擔心管理的線程ID得到回收(不太可能?)的情況。您還可以使用線程進行更多操作,而不是託管的ID。 – user7116 2009-05-28 18:14:35