静态方法中的局部变量是否安全?

如果我有一个带静态方法的静态类,如果多个线程调用它,方法中的局部变量是否安全?

static class MyClass { static int DoStuff(int n) { int x = n; // <--- Can this be modified by another thread? return x++; } } 

这个问题的答案说明当地人存储在堆栈上因此是线程安全的,这些问题是不完整的,也许是危险的错误。

线程在执行静态方法时是否创建了自己的范围?

您的问题包含常见错误。 C#中的“范围”纯粹是编译时的概念; “范围”是程序文本的一个区域,其中特定实体 (例如变量或类型)可以通过其非限定名称来引用。 范围有助于确定编译器如何将名称映射到名称所代表的概念。

线程不会在运行时创建“范围”,因为“范围”纯粹是编译时的概念。

局部变量的范围 – 松散地 – 与其生命周期相关联 ; 粗略地说,局部变量的运行时生命周期通常在控件线程输入对应于其作用域开头的代码时开始,并在控制线程离开时结束。 但是,如果编译器和运行时认为这样做是有效的或必要的,则它们都有相当大的自由裁量权来延长或缩短该生命周​​期。

特别是,迭代器块中的本地和匿名函数的封闭本地的生命周期延长到超出控制离开范围的点。

但是,这些都与线程安全无关。 所以,让我们放弃这个措辞严厉的问题,继续进行更好的措辞:

如果我有一个带静态方法的静态类,如果多个线程调用它,方法中的实例变量是否安全?

您的问题包含错误。 实例变量 是非静态字段 。 显然,静态类中没有非静态字段。 您将实例变量与局部变量混淆。 你打算问的问题是:

如果我有一个带静态方法的静态类,如果多个线程调用它,方法中的局部变量是否安全?

我没有直接回答这个问题,而是将其改为两个可以更容易回答的问题。

在什么情况下我需要使用锁定或其他特殊的线程安全技术来确保安全访问变量?

如果有两个线程,两个都可以访问变量,至少有一个线程正在改变它,并且至少有一个线程正在对它执行一些非primefaces操作,则需要这样做。

(我注意到可能还有其他因素在起作用。例如,如果你需要从每个线程中看到一致观察到的共享内存变量值,那么你需要使用特殊的技术,即使这些操作都是primefaces的.C#不会保证共享内存观察的顺序一致性,即使该变量被标记为volatile。)

超。 让我们专注于“两者都可以访问变量”部分。 在什么情况下两个线程都可以访问局部变量?

典型情况下,只能在声明它的方法中访问局部变量。 每个方法激活都会创建一个不同的变量,因此无论在不同的线程上激活该方法多少次,都不会在两个不同的线程上访问同一个变量。

但是,有一些方法可以在创建它的方法之外访问局部变量。

首先,“ref”或“out”参数可能是局部变量的别名,但CLR和C#语言都经过精心设计,因此只能通过声明方法调用的方法访问局部变量的别名。变量(直接或间接)。 因此,这应该仍然是线程安全的; 应该没有办法从一个线程到另一个线程获取ref,从而在线程之间共享变量。

其次,局部变量可能是lambda或匿名方法的封闭本地。 在这种情况下,局部变量不一定是线程安全的。 如果委托存储在共享内存中,则两个线程可以独立操作本地!

 static class Foo { private static Func f; public static int Bar() { if (Foo.f == null) { int x = 0; Foo.f = ()=>{ return x++; }; } return Foo.f(); } } 

这里“Bar”有一个局部变量“x”。 如果在多个线程上调用Bar,则首先线程竞争以确定谁设置Foo.f. 其中一人获胜。 从现在开始,在多个线程上调用Bar都会不安全地操作由获胜线程创建的委托捕获的相同局部变量x。 作为局部变量不是线程安全的保证

第三,迭代器块中的局部变量具有相同的问题:

 static class Foo { public static IEnumerable f; private static IEnumerable Sequence() { int x = 0; while(true) yield return x++; } public static Bar() { Foo.f = Sequence(); } } 

如果有人调用Foo.Bar()然后从两个不同的线程访问Foo.f,那么单个局部变量x也可以在两个不同的线程上进行不安全的变异。 (当然,运行迭代器逻辑的机制也不是线程安全的。)

第四,在标记为“不安全”的代码中,可以通过在线程之间共享指向本地的指针来跨线程共享局部变量。 如果您将代码块标记为“不安全”,那么有责任确保代码是线程安全的(如果需要)。 除非您知道自己在做什么,否则请勿关闭安全系统。