2009-05-28 13 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