代码之家  ›  专栏  ›  技术社区  ›  Mike Dinescu

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

  •  7
  • Mike Dinescu  · 技术社区  · 15 年前

    我正在编写一个在.NET库中可用的特殊数据结构,此数据结构的一个功能是,如果只有一个线程向它写入数据,并且只有一个线程从中读取数据,那么它将是线程安全的(读卡器线程和写器线程可以不同)。

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

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

    这就足够了吗,或者是否有其他更可靠的机制来实现这一点?

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

    3 回复  |  直到 15 年前
        1
  •  6
  •   JaredPar    15 年前

    当我遇到这种情况时,我使用了一个我写的叫做“三人行”的类。它的全部目的是记录当前线程,并抛出来自不同线程的无效访问。您必须手动进行检查,但它为您封装了少量的工作。

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

    关于主题的博客文章:

        2
  •  1
  •   Jeff Yates    15 年前

    您是否可以不要求读写方法采用线程或线程ID?然后,您可以将其与第一个调用它的代码进行比较,如果不匹配,则抛出异常或返回错误代码,或者忽略请求。

    否则,你的建议也会奏效。您只需要比较线程ID。

        3
  •  1
  •   user7116    15 年前

    与其比较线程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;
        }
    }