我正在编写一个可在.NET库中使用的特殊数据结构,并且该数据结构的一个特性是线程安全的,前提是只有一个线程向其写入数据,并且只有一个线程从中读取数据(读者线程和编写者线程可以不同)。
问题是如何强制所有Read操作都由同一个线程执行?
我的解决方案是捕获System.Threading.Thread.ManagedThreadID并在第一次读取时将其存储在私有成员中。然后,在后续读取时检查ManagedThreadID与已保存的一个,如果它们不同则抛出异常。
这是否足够,或者是否存在不同的更可靠的机制。
注意:要求此库在没有Windows.Forms上下文的情况下可用。
答案 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;
}
}