Reputation: 17329
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
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
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