Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static method local variables and thread-safety

Tags:

c#

static

With normal instance methods, local variables are thread safe.

If I have the following in a static method:

int i = 0;
i += 3;

Would this be thread-safe? Is there any catch?

Also, what exactly does it mean when each variable has its own stack? Does that mean its own stacktrace?

Thanks

like image 365
GurdeepS Avatar asked Feb 22 '10 22:02

GurdeepS


3 Answers

If the lines you posted are inside the method, then there's no reason why it shouldn't be threadsafe. The threads aren't interacting in any way - each thread sees a different i.

The catch comes if you try to share the value of i between threads, for example by making i a static field. Then it's possible to get a race condition where you get different results depending on timing.

Regarding your second question, each thread has its own stack, not each variable.

like image 126
Mark Byers Avatar answered Oct 01 '22 19:10

Mark Byers


Short answer is yes the following method is thread safe:

public static int CalcuateSomething( int number ) {
  int i = number * 10;
  return i;
}

All local variables are safe provided they don't point to a shared object on the heap.

Just as you have in the case of single thread applications the following invocations of this method will return different values.

CalculateSomething( 10 ) => 100
CalculateSomething( 20 ) => 200

Why is that? Because each invocation of the method number takes on different values, and therefore i will too. The value of i is not remembered after the function is over because i is allocated on the stack. In almost all languages functions are model on a stack. Each time you invoke a different method the current method is paused. A new method is pushed onto the call stack and invoked. When that method is finished the program unpauses the calling method and resumes where it left off (i.e. at the returnAddress). Any local variable defined within that method is apart of that method's stackframe. The stackframe for our method above could be thought of like this:

public Class StackFrameForCalculateSomething implements StackFrame {
  public int ReturnAddress;
  public int i = 0;
  public int number;
}

The stack could be thought of as a collection of StackFrame objects.

Stack callStack

Each time a new method is called the program might do something like the following:

StackFrameForCalculcateSomething s = new StackFrameForCalculateSomething();
s.returnAddress = instructionPointer;
s.number = 10;
callStack.push( s );
s.invoke();

StackFrameForCalculcateSomething s2 = new StackFrameForCalculateSomething();
s2.returnAddress = instructionPointer;
s2.number = 20;
callStack.push( s2 );
s2.invoke();

What does this mean for threading? Well in the case of threads you'd have multiple independent callStacks with their own collection. The reason access to local variables is safe is because there's no way for Thread 1's callStack to get access to Thread 2's callStack because they are separate objects. Just like in the single thread case s and s2 are different objects with different values of number. And so they are independent from each other. Consider s was in Thread 1 and s2 is Thread 2. Thread 1 and Thread 2 don't share any memory in common so it's thread safe.

Thread's don't share their stack frames. They do share the heap.

like image 34
chubbsondubs Avatar answered Oct 01 '22 20:10

chubbsondubs


First off, I assume by "threadsafe" you mean "behave as though certain operations are atomic when mutations happen on multiple threads." If that's not what you mean by "threadsafe" then please carefully define "threadsafe" before you ask questions about it. It seems that almost everyone who asks questions about thread safety on stack overflow has a different personal definition for what it means.

Second, local variables are not threadsafe. In particular, local variables which are closed-over outer variables of a lambda or anonymous method, or which are inside an iterator block, are not guaranteed to be threadsafe when mutated on multiple threads.

Local variables which are not closed-over outer variables of an anonymous function, and are not in an iterator block can only be mutated by the current thread, and are therefore safe from being mutated by multiple threads at once.

Also, what exactly does it mean when each variable has its own stack?

I have no idea what that means; variables do not have stacks. Threads have stacks.

like image 30
Eric Lippert Avatar answered Oct 01 '22 19:10

Eric Lippert