如何检测.NET中的跨线程访问(强制线程关联)?

时间:2009-05-28 17:38:49

标签: .net multithreading

我正在编写一个可在.NET库中使用的特殊数据结构,并且该数据结构的一个特性是线程安全的,前提是只有一个线程向其写入数据,并且只有一个线程从中读取数据(读者线程和编写者线程可以不同)。

问题是如何强制所有Read操作都由同一个线程执行?

我的解决方案是捕获System.Threading.Thread.ManagedThreadID并在第一次读取时将其存储在私有成员中。然后,在后续读取时检查ManagedThreadID与已保存的一个,如果它们不同则抛出异常。

这是否足够,或者是否存在不同的更可靠的机制。

注意:要求此库在没有Windows.Forms上下文的情况下可用。

3 个答案:

答案 0 :(得分: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 :(得分:1)

您是否可以不要求Read和Write方法获取线程或线程ID?然后你可以比较首先调用它的那个,如果它不匹配,抛出异常或返回错误代码,或忽略请求。

否则,你的建议也应该有效。您只需要比较线程ID。

答案 2 :(得分:1)

您应该在构建期间将ambient Thread存储在班级中,而不是比较线程ID。

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;
    }
}