gpt4 book ai didi

c# - 静态方法中的局部变量线程安全吗?

转载 作者:IT王子 更新时间:2023-10-29 04:18:05 26 4
gpt4 key购买 nike

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

static class MyClass {

static int DoStuff(int n) {

int x = n; // <--- Can this be modified by another thread?

return x++;
}
}

最佳答案

对此问题的回答是,哪些状态存储在堆栈上,因此是线程安全的,所以它们是不完整的,并且可能是错误的危险。

Do threads create their own scope when executing static methods?



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

线程不会在运行时创建“作用域”,因为“作用域”纯粹是一个编译时概念。

局部变量的范围(宽松地)与其生存期相关;粗略地讲,局部变量的运行时生存期通常在控制线程输入与其范围的开始相对应的代码时开始,并在控制线程离开时结束。但是,如果编译器和运行时认为有效或必要,则都可以酌情决定是否延长或缩短该生存期。

特别是,迭代器块中的局部变量和匿名函数的封闭局部变量的生存期延长到控制超出范围的程度。

但是,这与线程安全无关。因此,让我们放弃这个措辞不佳的问题,然后转为更好的措辞:

If I have a static class with a static method, are the instance variables within the method safe if multiple threads are calling it?



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

If I have a static class with a static method, are the local variables within the method safe if multiple threads are calling it?



与其直接回答这个问题,不如将其改写为两个更容易回答的问题。

Under what circumstances do I need to use locking or other special thread-safety techniques to ensure safe access to a variable?



如果有两个线程,两个都可以访问该变量,至少有一个线程正在对其进行变异,并且至少有一个线程对其执行了一些非原子操作,则需要这样做。

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

Super. Let's concentrate on that "both can access the variable" part. Under what circumstances can two threads both access a local variable?



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

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

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

其次,局部变量可能是lambda或匿名方法的封闭局部变量。 在这种情况下,局部变量不一定是线程安全的。 如果委托(delegate)存储在共享内存中,那么两个线程可以独立地操作本地!
static class Foo
{
private static Func<int> 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的调用都将不安全地操作由获胜线程创建的委托(delegate)捕获的同一局部变量x。 作为局部变量不能保证线程安全。

第三,迭代器块中的局部变量具有相同的问题:
static class Foo
{
public static IEnumerable<int> f;
private static IEnumerable<int> Sequence()
{
int x = 0;
while(true) yield return x++;
}
public static Bar() { Foo.f = Sequence(); }
}

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

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

关于c# - 静态方法中的局部变量线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7187943/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com