[C#] 메소드를 스레드로부터 안전하게 만드는 것은 무엇입니까? 규칙은 무엇입니까?

메소드를 스레드로부터 안전하게 만드는 것에 대한 전반적인 규칙 / 지침이 있습니까? 일회성 상황이 백만 건일 수 있지만 일반적으로 어떻습니까? 이것이 간단합니까?

  1. 메소드가 로컬 변수에만 액세스하는 경우 스레드 안전합니다.

그게 다야? 정적 메소드에도 적용됩니까?

@Cybis가 제공 한 한 가지 대답은 다음과 같습니다.

각 스레드는 자체 스택을 가져 오기 때문에 스레드간에 로컬 변수를 공유 할 수 없습니다.

정적 메소드도 마찬가지입니까?

메소드에 참조 객체가 전달되면 스레드 안전성이 손상됩니까? 나는 약간의 연구를 해왔고, 어떤 경우에 대해서는 많은 것이 있지만, 몇 가지 규칙을 사용하여 방법이 스레드 안전하다는 것을 보장하기 위해 따라야 할 지침을 정의 할 수 있기를 바랐습니다.

따라서 궁극적 인 질문은 “스레드 안전 방법을 정의하는 짧은 규칙 목록이 있습니까? 그렇다면 그렇다면 무엇입니까?”입니다.

편집
여기에는 많은 좋은 점이 있습니다. 이 질문에 대한 진정한 대답은 “스레드 안전을 보장하는 간단한 규칙은 없습니다”라고 생각합니다. 멋있는. 좋아. 그러나 일반적으로 나는 받아 들인 대답이 짧고 좋은 요약을 제공한다고 생각합니다. 항상 예외가 있습니다. 그러면 그렇게 해. 나는 그걸로 살 수 있습니다.



답변

메소드 (인스턴스 또는 정적)가 해당 메소드 내에서 범위가 지정된 변수 만 참조하는 경우 각 스레드에는 자체 스택이 있으므로 스레드 안전합니다.

이 경우 여러 스레드가 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;
    }
}

메소드가 로컬 범위 변수 만 참조하는 다른 클래스 메소드를 호출하는 경우에도 마찬가지입니다.

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;
    }
}

메소드가 (객체 상태) 속성 또는 필드 (인스턴스 또는 정적)에 액세스하는 경우 다른 스레드에서 값을 수정하지 않도록 잠금을 사용해야합니다.

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;
    }
}

구조체 나 불변이 아닌 메서드에 전달 된 모든 매개 변수는 메서드 범위 밖의 다른 스레드에 의해 변경 될 수 있습니다.

적절한 동시성을 보장하려면 잠금을 사용해야합니다.

자세한 정보는 잠금 문 C # 참조ReadWriterLockSlim을 참조 하십시오 .

lock 은 대부분 한 번에 하나의 기능을 제공하는 데 유용하며
ReadWriterLockSlim여러 독자와 단일 작성자가 필요한 경우 유용합니다.


답변

메소드가 로컬 변수에만 액세스하는 경우 스레드 안전합니다. 그게 다야?

절대로 아닙니다. 그럼에도 불구하고 스레드 안전하지 않은 단일 스레드에서 액세스하는 단일 로컬 변수로 프로그램을 작성할 수 있습니다.

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

정적 메소드에도 적용됩니까?

절대적으로하지.

@Cybis가 제공 한 한 가지 대답은 “각 스레드가 자체 스택을 가져 오기 때문에 로컬 변수를 스레드간에 공유 할 수 없습니다.”

절대적으로하지. 로컬 변수의 특징은 임시 풀에 할당 된 것이 아니라 로컬 범위 내에서만 볼 수 있다는 것입니다 . 완벽하게 합법적이며 두 개의 다른 스레드에서 동일한 로컬 변수에 액세스 할 수 있습니다. 익명 메소드, 람다, 반복자 블록 또는 비동기 메소드를 사용하여이를 수행 할 수 있습니다.

정적 메소드도 마찬가지입니까?

절대적으로하지.

메소드에 참조 객체가 전달되면 스레드 안전성이 손상됩니까?

아마도.

나는 약간의 연구를 해왔고, 어떤 경우에 대해서는 많은 것이 있지만, 몇 가지 규칙을 사용하여 방법이 스레드 안전하다는 것을 보장하기 위해 따라야 할 지침을 정의 할 수 있기를 바랐습니다.

실망으로 사는 법을 배워야 할 것입니다. 이것은 매우 어려운 주제입니다.

그래서 궁극적 인 질문은 다음과 같습니다. “스레드 안전 방법을 정의하는 짧은 규칙 목록이 있습니까?

아니. 이전 예제에서 보았 듯이 빈 메소드는 스레드로부터 안전하지 않을 수 있습니다 . “방법이 올바른지 확인 하는 짧은 규칙 목록이 있습니까? ” 아니 없어. 스레드 안전성은 매우 복잡한 종류의 정확성에 지나지 않습니다.

또한 질문을한다는 사실은 나사산 안전에 대한 근본적인 오해를 나타냅니다. 스레드 안전성은 프로그램 의 로컬 속성이 아닌 글로벌 입니다. 올바르게 얻기가 어려운 이유 는 안전을 위해 전체 프로그램의 스레딩 동작에 대한 완전한 지식이 있어야 하기 때문 입니다.

다시 한 번, 내 예를 살펴보십시오. 모든 방법은 사소 합니다. 프로그램이 교착 상태가되는 “전역”레벨에서 메소드가 서로 상호 작용하는 방식입니다. 모든 방법을보고 “안전한”것으로 확인한 다음 전체 프로그램이 안전하다고 기대할 수는 없습니다. 중공이 아닙니다. 집의 빈 공간은 모든 부분의 속성이 아니라 전체의 세계적인 속성입니다.


답변

단단하고 빠른 규칙은 없습니다.

다음은 .NET에서 코드 스레드를 안전하게 만드는 몇 가지 규칙과 왜 이것이 좋은 규칙이 아닌지입니다.

  1. 함수와 함수가 호출하는 모든 함수는 순수해야하며 (부작용 없음) 지역 변수를 사용해야합니다. 이렇게하면 코드를 스레드로부터 안전하게 만들 수 있지만 .NET에서는이 제한으로 수행 할 수있는 흥미로운 작업이 거의 없습니다.
  2. 공통 객체에서 작동하는 모든 기능 lock은 공통적 인 것이 어야합니다 . 모든 잠금은 동일한 순서로 수행해야합니다. 이렇게하면 코드 스레드가 안전 해지지 만 엄청나게 느려질 수 있으며 여러 스레드를 사용하지 않을 수도 있습니다.

코드 스레드를 안전하게 만드는 규칙은 없으며, 수행 할 수있는 유일한 일은 코드가 실제로 실행되는 횟수에 관계없이 코드가 작동하는지 확인하는 것입니다. 각 스레드는 어느 시점에서든 중단 될 수 있습니다. 자체 상태 / 위치 및 공통 객체에 액세스하는 각 기능 (정적 또는 기타)에 대해


답변

객체 잠금, 상태 비 저장 또는 불변을 사용하여 동기화해야합니다.

링크 : http://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html


답변