C# 确保类只能由实例化它的线程使用
我创建了一个非线程安全的类,如果假设它是线程安全的,那么它可能会导致错误。当我努力使我的类线程安全时,我想让实例只由一个线程使用。目前,我的实现是检查当前线程是否与用于在每个公开点构造实例的线程相同C# 确保类只能由实例化它的线程使用,c#,thread-safety,C#,Thread Safety,我创建了一个非线程安全的类,如果假设它是线程安全的,那么它可能会导致错误。当我努力使我的类线程安全时,我想让实例只由一个线程使用。目前,我的实现是检查当前线程是否与用于在每个公开点构造实例的线程相同 public class NotThreadSafeClass { private readonly int _creatorThreadId; public NotThreadSafeClass() { _creatorThreadId = Thread.
public class NotThreadSafeClass
{
private readonly int _creatorThreadId;
public NotThreadSafeClass()
{
_creatorThreadId = Thread.CurrentThread.ManagedThreadId;
}
public string ExposedProp
{
get
{
AssertSameThread();
return "My Prop";
}
}
public void ExposedMethod()
{
AssertSameThread();
/* Do stuff */
}
private void AssertSameThread()
{
Throw.If(_creatorThreadId != Thread.CurrentThread.ManagedThreadId,
@"NotThreadSafeClass is not thread safe. Please don't use
the same instance of NotThreadSafeClass in multiple threads.");
}
}
注意:Throw.If在中定义
这种模式似乎可行,但如果开发人员忘记将此检查添加到任何新的曝光中,那么它会很麻烦,并且容易受到bug的影响。是否有更安全和/或更优雅的方法来确保实例仅由一个线程使用?编辑:将
ThreadLocal
移动到类声明内的私有字段
除非我完全误解,ThreadLocal
应该满足您的需要。例如:
class Foo {
private ThreadLocal<int> _internalState;
public Foo() {
_internalState = new ThreadLocal<int>();
}
public int IntValue {
get { return _internalState.Value; }
set { _internalState.Value = value; }
}
public override string ToString() {
return _internalState.ToString();
}
}
class Program {
public static void Main(string[] args) {
Demonstrate();
}
static void Demonstrate() {
var local = new Foo {IntValue = 5};
Console.WriteLine("Start thread value: {0}", local.IntValue);
new Thread(() => {
local.IntValue += 5;
Console.WriteLine("New thread value: {0}", local.IntValue);
}).Start();
local.IntValue += 10;
Console.WriteLine("Start thread value: {0}", local.IntValue);
}
}
我认为,如果不使用AOP框架,您将不得不在自己的代码中“拦截”对类的方法/属性的所有此类访问,就像您描述的那样 我在想,或者 语言/框架中没有为此构建任何内容
干杯只是好奇地。。。为什么只有创建类的线程才能使用它很重要?你的意思是像非泛型重写
Throw.If
是有害的,因为它会给你留下一个非描述性的异常。它也不是正确的重用级别。将ThreadId检查和抛出(正确描述的异常)放在一个helper函数中,这样至少检查的负担会更低,因此跳过的可能性更小。@BenVoigt,很好的调用。实际上,我正在使用一个helper函数,它使用Throw.If
来抛出一个更具体的异常消息。我只是排除了那个helper函数来简化我的示例。我将修改我的示例。@bryancrossby我正在编写一个与NUnit交互的组件。我只是不相信我的类和NUnit之间的交互是否正常工作,因为当我尝试在不同的线程中使用组件时,我的单元测试显示出意外的行为。@RobertHarvey不是。这很好,我认为get是我的90%!每次我们第一次尝试实例化这个类时,我都会抛出一个异常。通过使用闭合布尔函数,该功能应该很容易实现。我必须做一些重构来实现这一点,但我认为它应该适合我。谢谢@StevenWexlerThreadLocal
未密封,因此您可以修改其行为以执行您需要的操作-不确定是否通过
Start thread value: 5
Start thread value: 15
New thread value: 5