关于c#:什么使方法线程安全?

What Makes a Method Thread-safe? What are the rules?

是否有使方法线程安全的总体规则/准则?我知道可能有一百万个一次性的情况,但一般情况下呢?这很简单吗?

  • 如果一个方法只访问局部变量,那么它是线程安全的。
  • 是这样吗?这也适用于静态方法吗?

    由CybIS提供的一个答案是:

    Local variables cannot be shared among threads because each thread gets its own stack.

    静态方法也是这样吗?

    如果一个方法被传递给一个引用对象,这会破坏线程安全吗?我做过一些研究,关于某些案例有很多,但是我希望能够通过使用一些规则来定义要遵循的准则,以确保方法是线程安全的。

    所以,我想我的终极问题是:"是否有一个简短的规则列表来定义线程安全方法?如果是,他们是什么?"

    编辑< BR/>这里有很多好的地方。我认为这个问题的真正答案是:"没有简单的规则来确保线程安全。"酷。好的。但总的来说,我认为被接受的答案提供了一个好的、简短的总结。总有例外。就这样吧。我可以忍受。


    如果一个方法(实例或静态)只引用该方法范围内的变量,那么它是线程安全的,因为每个线程都有自己的堆栈:

    在这种情况下,多个线程可以同时调用ThreadSafeMethod,而不会出现问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Thing
    {
        public int ThreadSafeMethod(string parameter1)
        {
            int number; // each thread will have its own variable for number.
            number = parameter1.Length;
            return number;
        }
    }

    如果该方法调用只引用本地作用域变量的其他类方法,则也是如此:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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;
        }
    }

    如果方法访问任何(对象状态)属性或字段(实例或静态),则需要使用锁来确保值不会被其他线程修改。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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;
        }
    }

    您应该知道,传递给方法的任何参数(既不是结构也不是不可变的)都可能被方法范围之外的另一个线程改变。

    为了确保适当的并发性,您需要使用锁定。

    有关更多信息,请参阅lock statement c reference和readwriterlockslim。

    锁主要用于提供一次一个的功能,
    如果您需要多个读者和单个作者,ReadWriterLockSlim非常有用。


    If a method only accesses local variables, it's thread safe. Is that it?

    绝对不是。您可以编写一个程序,其中只有一个本地变量可以从单个线程访问,但该线程不是线程安全的:

    https://stackoverflow.com/a/8883117/88656

    Does that apply for static methods as well?

    绝对不是。

    One answer, provided by @Cybis, was:"Local variables cannot be shared among threads because each thread gets its own stack."

    绝对不是。局部变量的区别特性是它只能从局部范围内可见,而不是在临时池上分配。从两个不同的线程访问相同的本地变量是完全合法的。可以通过使用匿名方法、lambdas、迭代器块或异步方法来实现这一点。

    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?

    不。正如您在前面的示例中看到的,空方法可以是非线程安全的。您不妨问"是否有一个简短的规则列表可以确保方法是正确的"。不,没有。线程安全只是一种极其复杂的正确性。

    此外,您提出问题的事实表明您对线程安全的基本误解。线程安全是全局的,而不是程序的本地属性。之所以如此难以正确处理,是因为您必须完全了解整个程序的线程行为,以确保其安全性。

    再来看看我的例子:每个方法都是琐碎的。正是这些方法在"全局"级别上相互作用的方式导致了程序死锁。你不能把每种方法都看成是"安全的",然后期望整个程序是安全的,这比你能得出的结论更重要,因为你的房子是由100%的非空心砖建造的,所以房子也是非空心的。空旷的房子是一个整体的全球性财产,而不是其各部分财产的总和。


    没有硬性规定。

    以下是一些使.NET中的代码线程安全的规则,以及为什么这些规则不好:

  • 函数及其调用的所有函数必须是纯函数(无副作用)并使用局部变量。虽然这将使您的代码线程安全,但在.NET中,您可以用这个限制做的有趣的事情也很少。
  • 在公共对象上运行的每个函数必须在公共对象上执行cx1〔0〕。所有锁必须按相同的顺序进行。这将使代码线程安全,但速度会非常慢,您最好不要使用多个线程。
  • 没有使代码线程安全的规则,您唯一能做的就是确保您的代码可以工作,无论它被主动执行多少次,每个线程都可以在任何点被中断,每个线程都处于自己的状态/位置,这对于访问公共对象的每个函数(静态或其他)都是如此。


    它必须使用对象锁、无状态或不可变进行同步。

    链接:http://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html