Steven Wexler
Steven Wexler

Reputation: 17329

Guarantee that a class can only be used by the thread that instantiated it

I've created a class that is not thread-safe and can lead to bad bugs if assumed to be thread-safe. While I work to make my class thread-safe, I'd like to make instances only usable by one thread. Currently my implementation is to check that the current thread is the same as the thread used to construct the instance at every exposure point.

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

Note: Throw.If is defined in http://www.codeducky.org/10-utilities-c-developers-should-know-part-one/

This pattern seems to work, but it's cumbersome and susceptible to bugs if a developer forgets to add this check to any new exposures. Is there a safer and/or more elegant way to ensure that an instance is only used by one thread?

Upvotes: 3

Views: 129

Answers (2)

jdphenix
jdphenix

Reputation: 15445

Edit: Moved ThreadLocal<T> to a private field inside the class declaration.

Unless I completely misunderstand, ThreadLocal<T> should meet your needs. An example:

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

Sample output:

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

Upvotes: 1

Luc Morin
Luc Morin

Reputation: 5380

I think that short of using an AOP framework, you will have to "intercept" all such access to your class' methods/properties in your own code, just like you're describing.

I'm thinking Ninject's Interception Extension, or PostSharp

Nothing is built into the language/framework for this.

Cheers

Upvotes: 2

Related Questions