保证类只能由实例化它的线程使用

时间:2014-03-17 23:21:03

标签: c# thread-safety

我创建了一个非线程安全的类,如果假设是线程安全的,可能会导致错误。虽然我努力使我的类具有线程安全性,但我希望使实例只能由一个线程使用。目前我的实现是检查当前线程是否与用于在每个曝光点构造实例的线程相同。

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在http://www.codeducky.org/10-utilities-c-developers-should-know-part-one/

中定义

这种模式似乎有效,但如果开发人员忘记将此检查添加到任何新的曝光中,那么它很麻烦且容易受到错误的影响。是否有更安全和/或更优雅的方法来确保实例仅由一个线程使用?

2 个答案:

答案 0 :(得分:2)

我认为,如果没有使用AOP框架,你必须"拦截"所有这样的访问你的班级'您自己的代码中的方法/属性,就像您正在描述的那样。

我在想Ninject's Interception ExtensionPostSharp

此语言/框架没有内置任何内容。

干杯

答案 1 :(得分:1)

编辑:将ThreadLocal<T>移动到类声明中的私有字段。

除非我完全误解,否则ThreadLocal<T>应该满足您的需求。一个例子:

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

示例输出:

Start thread value: 5
Start thread value: 15
New thread value: 5