C# 什么使方法线程安全?规则是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9848067/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What Makes a Method Thread-safe? What are the rules?
提问by Bob Horn
Are there overall rules/guidelines for what makes a method thread-safe? I understand that there are probably a million one-off situations, but what about in general? Is it this simple?
是否有使方法线程安全的总体规则/指南?我知道可能有一百万种一次性情况,但一般情况下呢?有这么简单吗?
- If a method only accesses local variables, it's thread safe.
- 如果一个方法只访问局部变量,它就是线程安全的。
Is that it? Does that apply for static methods as well?
是这样吗?这也适用于静态方法吗?
One answer, provided by @Cybis, was:
@Cybis 提供的一个答案是:
Local variables cannot be shared among threads because each thread gets its own stack.
局部变量不能在线程之间共享,因为每个线程都有自己的堆栈。
Is that the case for static methods as well?
静态方法也是这样吗?
If a method is passed a reference object, does that break thread safety? I've done some research, and there is a lot out there about certain cases, but I was hoping to be able to define, by using just a few rules, guidelines to follow to make sure a method is thread safe.
如果向方法传递引用对象,是否会破坏线程安全?我做了一些研究,并且有很多关于某些情况的研究,但我希望能够通过仅使用一些规则来定义要遵循的准则,以确保方法是线程安全的。
So, I guess my ultimate question is: "Is there a short list of rules that define a thread-safe method? If so, what are they?"
所以,我想我的最终问题是:“是否有一个简短的规则列表来定义线程安全方法?如果有,它们是什么?”
EDIT
A lot of good points have been made here. I think the real answer to this question is: "There are no simple rules to ensure thread safety." Cool. Fine. But in generalI think the accepted answer provides a good, short summary. There are always exceptions. So be it. I can live with that.
编辑这里
有很多优点。我认为这个问题的真正答案是:“没有简单的规则来确保线程安全。” 凉爽的。美好的。但总的来说,我认为接受的答案提供了一个很好的简短总结。总有例外。就这样吧。我可以忍受这一点。
采纳答案by Trevor Pilley
If a method (instance or static) only references variables scoped within that method then it is thread safe because each thread has its own stack:
如果一个方法(实例或静态)只引用该方法范围内的变量,那么它是线程安全的,因为每个线程都有自己的堆栈:
In this instance, multiple threads could call ThreadSafeMethodconcurrently without issue.
在这种情况下,多个线程可以ThreadSafeMethod毫无问题地并发调用。
public class Thing
{
public int ThreadSafeMethod(string parameter1)
{
int number; // each thread will have its own variable for number.
number = parameter1.Length;
return number;
}
}
This is also true if the method calls other class method which only reference locally scoped variables:
如果该方法调用其他只引用局部范围变量的类方法,这也是正确的:
public class Thing
{
public int ThreadSafeMethod(string parameter1)
{
int number;
number = this.GetLength(parameter1);
return number;
}
private int GetLength(string value)
{
int length = value.Length;
return length;
}
}
If a method accesses any (object state) properties or fields (instance or static) then you need to use locks to ensure that the values are not modified by a different thread.
如果一个方法访问任何(对象状态)属性或字段(实例或静态),那么您需要使用锁来确保这些值不会被其他线程修改。
public class Thing
{
private string someValue; // all threads will read and write to this same field value
public int NonThreadSafeMethod(string parameter1)
{
this.someValue = parameter1;
int number;
// Since access to someValue is not synchronised by the class, a separate thread
// could have changed its value between this thread setting its value at the start
// of the method and this line reading its value.
number = this.someValue.Length;
return number;
}
}
You should be aware that any parameters passed in to the method which are not either a struct or immutable could be mutated by another thread outside the scope of the method.
您应该知道,任何传递给方法的参数都不是结构体或不可变的,可能会被方法范围之外的另一个线程改变。
To ensure proper concurrency you need to use locking.
为了确保适当的并发性,您需要使用锁定。
for further information see lock statement C# referenceand ReadWriterLockSlim.
有关更多信息,请参阅lock 语句 C# 参考和ReadWriterLockSlim。
lockis mostly useful for providing one at a time functionality, ReadWriterLockSlimis useful if you need multiple readers and single writers.
lock主要用于一次提供一个功能,ReadWriterLockSlim如果您需要多个读取器和单个写入器,则非常有用。
回答by kasavbere
It must be synchronized, using an object lock, stateless, or immutable.
它必须是同步的、使用对象锁、无状态或不可变的。
link: http://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html
链接:http: //docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html
回答by earlNameless
There is no hard and fast rule.
没有硬性规定。
Here are some rules to make code thread safe in .NET and why these are not good rules:
以下是一些使 .NET 中的代码线程安全的规则,以及为什么这些规则不是好的规则:
- Function and all functions it calls must be pure (no side effects) and use local variables. Although this will make your code thread-safe, there is also very little amount of interesting things you can do with this restriction in .NET.
- Every function that operates on a common object must
lockon a common thing. All locks must be done in same order. This will make the code thread safe, but it will be incredibly slow, and you might as well not use multiple threads. - ...
- 函数及其调用的所有函数必须是纯函数(无副作用)并使用局部变量。尽管这将使您的代码成为线程安全的,但在 .NET 中,您可以利用此限制做很少的有趣的事情。
- 每个作用于共同对象的函数都必须作用
lock于共同的事物。所有锁定必须按相同顺序完成。这将使代码线程安全,但速度会非常慢,您最好不要使用多线程。 - ...
There is no rule that makes the code thread safe, the only thing you can do is make sure that your code will work no matter how many times is it being actively executed, each thread can be interrupted at any point, with each thread being in its own state/location, and this for each function (static or otherwise) that is accessing common objects.
没有任何规则可以使代码线程安全,您唯一能做的就是确保您的代码无论被主动执行多少次都能正常工作,每个线程都可以在任何时候中断,每个线程都在它自己的状态/位置,这适用于访问公共对象的每个函数(静态或其他)。
回答by Eric Lippert
If a method only accesses local variables, it's thread safe. Is that it?
如果一个方法只访问局部变量,它就是线程安全的。是这样吗?
Absolultely not. You can write a program with only a single local variable accessed from a single thread that is nevertheless not threadsafe:
绝对不是。您可以编写一个程序,其中只包含从单个线程访问的单个局部变量,但不是线程安全的:
https://stackoverflow.com/a/8883117/88656
https://stackoverflow.com/a/8883117/88656
Does that apply for static methods as well?
这也适用于静态方法吗?
Absolutely not.
绝对不。
One answer, provided by @Cybis, was: "Local variables cannot be shared among threads because each thread gets its own stack."
@Cybis 提供的一个答案是:“局部变量不能在线程之间共享,因为每个线程都有自己的堆栈。”
Absolutely not. The distinguishing characteristic of a local variable is that it is only visible from within the local scope, not that it is allocated on the temporary pool. It is perfectly legal and possible to access the same local variable from two different threads.You can do so by using anonymous methods, lambdas, iterator blocks or async methods.
绝对不。局部变量的显着特征是它仅在局部作用域内可见,而不是在临时池中分配。从两个不同的线程访问同一个局部变量是完全合法的并且是可能的。您可以通过使用匿名方法、lambda、迭代器块或异步方法来实现。
Is that the case for static methods as well?
静态方法也是这样吗?
Absolutely not.
绝对不。
If a method is passed a reference object, does that break thread safety?
如果向方法传递引用对象,是否会破坏线程安全?
Maybe.
也许。
I've done some research, and there is a lot out there about certain cases, but I was hoping to be able to define, by using just a few rules, guidelines to follow to make sure a method is thread safe.
我做了一些研究,并且有很多关于某些情况的研究,但我希望能够通过仅使用一些规则来定义要遵循的准则,以确保方法是线程安全的。
You are going to have to learn to live with disappointment. This is a very difficult subject.
你将不得不学会忍受失望。这是一个非常困难的课题。
So, I guess my ultimate question is: "Is there a short list of rules that define a thread-safe method?
所以,我想我的最终问题是:“是否有一个简短的规则列表来定义线程安全方法?
Nope. As you saw from my example earlier an empty method can be non-thread-safe. You might as well ask "is there a short list of rules that ensures a method is correct". No, there is not. Thread safety is nothing more than an extremely complicated kind of correctness.
不。正如您从我之前的示例中看到的,空方法可以是非线程安全的。您不妨问“是否有确保方法正确的规则的简短列表”。不,那里没有。线程安全无非是一种极其复杂的正确性。
Moreover, the fact that you are asking the question indicates your fundamental misunderstanding about thread safety. Thread safety is a global, not a localproperty of a program. The reason why it is so hard to get right is because you must have a complete knowledge of the threading behaviour of the entire programin order to ensure its safety.
此外,您提出这个问题的事实表明您对线程安全的根本误解。线程安全是程序的全局属性,而不是局部属性。之所以这么难做对,是因为你必须对整个程序的线程行为有一个完整的了解,才能保证它的安全。
Again, look at my example: every method is trivial. It is the way that the methods interact with each other at a "global" level that makes the program deadlock. You can't look at every method and check it off as "safe" and then expect that the whole program is safe, any more than you can conclude that because your house is made of 100% non-hollow bricks that the house is also non-hollow. The hollowness of a house is a global property of the whole thing, not an aggregate of the properties of its parts.
再看看我的例子:每个方法都是微不足道的。正是这些方法在“全局”级别相互交互的方式导致程序死锁。您不能查看每一种方法并将其检查为“安全”,然后期望整个程序是安全的,正如您可以得出结论,因为您的房子是由 100% 非空心砖制成的房子也是非空心。房屋的空心是整个事物的整体属性,而不是其各部分属性的集合。

