简体   繁体   English

静态函数并发ASP.NET

[英]Static Function Concurrency ASP.NET

If you have two threads invoking a static function at the same moment in time, is there a concurrency risk? 如果你有两个线程在同一时刻调用静态函数,是否存在并发风险? And if that function uses a static member of the class, is there even a bigger problem? 如果该函数使用类的静态成员,是否还有更大的问题?

  • Are the two calls seperated from each other? 这两个电话是否彼此分开? (the function is like copied for the two threads?) (该函数就像复制了两个线程一样?)
  • Are they automatically queued? 它们会自动排队吗?

For instance in next example, is there a risk? 例如,在下一个例子中,是否存在风险?

private static int a = 5;

public static int Sum()
{
    int b = 4;
    a = 9;
    int c = a + b;
    return c;
}

And next example, is there a risk? 接下来的例子,是否存在风险?

public static int Sum2()
{
   int a = 5;
   int b = 4;
   int c = a + b;
   return c;
}

Update: And indeed, if both functions are in the same class, what is the risk then? 更新:事实上,如果两个函数属于同一个类,那么风险是什么?

thx, Lieven Cardoen thx,Lieven Cardoen

Yes, there is a concurrency risk when you modify a static variable in static methods. 是的,在静态方法中修改静态变量时存在并发风险。

The static functions themselves have distinct sets of local variables, but any static variables are shared. 静态函数本身具有不同的局部变量集,但是共享任何静态变量。

In your specific samples you're not being exposed, but that's just because you're using constants (and assigning the same values to them). 在您的特定样本中,您没有被暴露,但这只是因为您正在使用常量(并为它们分配相同的值)。 Change the code sample slightly and you'll be exposed. 稍微更改代码示例,您将被暴露。

Edit: 编辑:

If you call both Sum1() AND Sum2() from different threads you're in trouble, there's no way to guarantee the value of a and b in this statement: int c = a + b; 如果通话双方 SUM1()和你就麻烦了不同的线程SUM2(),有没有办法保证的这个说法和b的值:INT C = A + B;

private static int a = 5;

public static int Sum1()
{
    int b = 4;
    a = 9;
    int c = a + b;
    return c;
}

public static int Sum2()
{
   int b = 4;
   int c = a + b;
   return c;
}

You can also achieve concurrency problems with multiple invocations of a single method like this: 您还可以通过多次调用单个方法来实现并发问题,如下所示:

public static int Sum3(int currentA)
{
   a = currentA;
   int b = 4;
   int c = a + b;
   int d = a * b; // a may have changed here
   return c + d;
}

The issue here is that the value of a may change mid-method due to other invocations changing it. 这里的问题是a的值可能会因为其他调用改变它而改变中间方法。

Yes, there is a risk. 是的,存在风险。 That's why you'll see in MSDN doc, it will often say "This class is threadsafe for static members" (or something like that). 这就是为什么你会在MSDN文档中看到,它会经常说“这个类对于静态成员是线程安全的”(或类似的东西)。 It means when MS wrote the code, they intentionally used synchronization primitives to make the static members threadsafe. 这意味着当MS编写代码时,他们故意使用同步原语来使静态成员线程安全。 This is common when writing libraries and frameworks, because it is easier to make static members threadsafe than instance members, because you don't know what the library user is going to want to do with instances. 这在编写库和框架时很常见,因为静态成员线程安全比实例成员更容易,因为您不知道库用户想要对实例做什么。 If they made instance members threadsafe for many of the library classes, they would put too many restrictions on you ... so often they let you handle it. 如果他们为许多库类提供实例成员线程安全,他们会对你施加太多限制......所以他们经常让你处理它。

So you likewise need to make your static members threadsafe (or document that they aren't). 所以你同样需要让你的静态成员线程安全(或者说它们不是文档)。

By the way, static constructors are threadsafe in a sense. 顺便说一下,静态构造函数在某种意义上是线程安全的。 The CLR will make sure they are called only once and will prevent 2 threads from getting into a static constructor. CLR将确保它们只被调用一次,并防止2个线程进入静态构造函数。

EDIT: Marc pointed out in the comments an edge case in which static constructors are not threadsafe. 编辑:Marc在评论中指出了一个边缘情况,其中静态构造函数不是线程安全的。 If you use reflection to explicitly call a static constructor, apparently you can call it more than once. 如果使用反射来显式调用静态构造函数,显然你可以多次调用它。 So I revise the statement as follows: as long as you are relying on the CLR to decide when to call your static constructor, then the CLR will prevent it from being called more than once, and it will also prevent the static ctor from being called re-entrantly. 所以我修改语句如下:只要你依靠CLR来决定何时调用静态构造函数,那么CLR将阻止它被多次调用,并且它也会阻止静态ctor被调用重新entrantly。

See here for a discussion on local variables. 有关局部变量的讨论,请参见此处 before your edit neither of the above methods themselves presented a concurrency risk; 在您编辑之前 ,上述方法本身都没有出现并发风险; the local variables are all independent per call; 局部变量每次调用都是独立的; the shared state ( static int a ) is visible to multiple threads, but you don't mutate it, and you only read it once. 共享状态( static int a )对多个线程是可见的,但是你不要改变它,你只读它一次。

If you did something like: 如果你做了类似的事情:

if(a > 5) {
    Console.WriteLine(a + " is greater than 5");
} // could write "1 is greater than 5"

it would (in theory) not be safe, as the value of a could be changed by another thread - you would typically either synchronize access (via lock etc), or take a snapshot: 它会(理论上) 不会是安全的,因为的价值可能被另一个线程改变-你会通常是同步连接(通过lock等),或采取快照:

int tmp = a;
if(tmp > 5) {
   Console.WriteLine(tmp + " is greater than 5");
}

If you are editing the value, you would almost certainly require synchronization. 如果您正在编辑该值,则几乎肯定需要同步。

In your two examples, there is no thread safety issues because each call to the function will have it's own copy of the local variables on the stack, and in your first example with 'a' being a static variable, you never change 'a', so there is no problem. 在你的两个例子中,没有线程安全问题,因为对函数的每次调用都会在堆栈中拥有它自己的局部变量副本,而在你的第一个例子中,'a'是一个静态变量,你永远不会改变'a' ,所以没有问题。

If you change the value in 'a' in your first example you will have a potential concurrency problem. 如果在第一个示例中更改“a”中的值,则可能存在潜在的并发问题。

如果变量的范围包含在静态函数中,则没有风险,但函数范围之外的变量(静态/共享)肯定会产生并发风险

Static methods in OO are no difference from "just" functions in procedural programming. OO中的静态方法与过程编程中的“仅”函数没有区别。 Unless you store some state inside static variable there is no risk at all. 除非您在静态变量中存储某些状态,否则根本没有风险。

您将“ASP.NET”放在问题标题中,这篇博文是对ASP.NET中使用ThreadStatic关键字时的问题的一个很好的总结: http//piers7.blogspot.com/2005/11/threadstatic-callcontext- and_02.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM