静态方法局部变量和线程安全性

时间:2010-02-22 22:39:08

标签: c# static

使用普通的实例方法,局部变量是线程安全的。

如果我在静态方法中有以下内容:

int i = 0;
i += 3;

这是线程安全的吗?有没有捕获?

此外,当每个变量都有自己的堆栈时,它究竟意味着什么?这是否意味着它自己的堆栈跟踪?

由于

4 个答案:

答案 0 :(得分:15)

如果您发布的行在方法内,那么就没有理由说它不应该是线程安全的。线程没有以任何方式交互 - 每个线程看到不同的i

如果您尝试在线程之间共享i的值,则会出现问题,例如通过使i成为静态字段。然后就可以得到一个竞争条件,你可以根据时间得到不同的结果。

关于第二个问题,每个线程都有自己的堆栈,而不是每个变量。

答案 1 :(得分:7)

首先,我认为“线程安全”是指“当多个线程发生突变时,某些操作就像某些操作是原子的”。如果这不是你所说的“线程安全”,那么在你提出问题之前,请仔细定义“threadsafe”。看起来几乎所有在堆栈溢出时询问线程安全问题的人都有不同的个人定义。

其次,局部变量不是线程安全。特别是,在多个线程上进行突变时,无法保证局部变量是lambda或匿名方法的封闭外部变量,或者是迭代器块内部的局部变量。

本地变量不是匿名函数的外部变量,不在迭代器块中,只能由当前线程进行变异,因此不会被多个线程一次性变异。

  

此外,当每个变量都有自己的堆栈时,它究竟意味着什么?

我不知道这意味着什么; 变量没有堆栈。 线程有堆栈。

答案 2 :(得分:5)

简短回答是肯定以下方法是线程安全的:

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

所有局部变量都是安全的,只要它们不指向堆上的共享对象。

就像单线程应用程序一样,此方法的以下调用将返回不同的值。

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

为什么?因为方法编号的每次调用都采用不同的值,因此我也会这样做。函数结束后,i的值不会被记住,因为i是在堆栈上分配的。在几乎所有语言中,函数都是堆栈上的模型。每次调用不同的方法时,当前方法都会暂停。将新方法推送到调用堆栈并调用。当该方法完成时,程序取消调用调用方法并从中断处继续(即在returnAddress处)。在该方法中定义的任何局部变量都是该方法的堆栈帧的一部分。上面我们方法的堆栈框架可以这样想:

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

可以将堆栈视为StackFrame对象的集合。

堆栈callStack

每次调用新方法时,程序可能会执行以下操作:

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

这对线程意味着什么?好吧,在线程的情况下,你有多个独立的callStacks和他们自己的集合。访问局部变量的原因是安全的,因为Thread 1的callStack无法访问Thread 2的callStack,因为它们是独立的对象。就像在单线程情况下,s和s2是具有不同数字值的不同对象。所以他们彼此独立。考虑s在线程1中,s2是线程2.线程1和线程2不共享任何共同的内存,因此它是线程安全的。

线程不共享其堆栈帧。他们分享堆。

答案 3 :(得分:0)

这是一个示例,其中包含一个(简单化)示例,以帮助扩展Mark所说的内容:

void Main()
{   
    for (int x = 0; x < 10; x++)
    {
        ThreadPool.QueueUserWorkItem(z=> myClass.DoSomething());
    }

}
public class myClass
{
    public static void DoSomething()
    {
        int i = 0;
        Console.WriteLine (i += 3);
    }
}

输出: 3 3 3 3 3 3 3 3 3 3 3