문제

나는 여전히 약간의 불분명한 경우 및 포장 잠금 주변에 어떤 코드입니다.나의 일반 규칙의-엄지 손가락은 작업에서 잠금을 때 그것을 읽거나 쓰는 정적 변수입니다.그러나 때는 정적 변수를 읽기(예:그것은 읽기 전용 중에 설정되는 유형을 초기화),액세스하지 않 포장해야에 잠금 문을,오른쪽?나는 최근 일부를 보았는 코드는 다음 예제와 같이,그리고 그것은 나에게 있다고 생각할 수 있다 약간의 차이에 다중 스레딩 기술:

class Foo
{
    private static readonly string bar = "O_o";

    private bool TrySomething()
    {
        string bar;

        lock(Foo.objectToLockOn)
        {
            bar = Foo.bar;          
        }       

        // Do something with bar
    }
}

지 않는 의미하는 이유가 거기에 의해 동시성 문제로 읽는가?

또한,이 예는 다른 질문입니다.중 하나 이러한 다른 것보다 더 나은?(E.g.예를 두 개의 잠금을 보유한다.) 내가를 분해 할 수 있었다 MSIL...

class Foo
{
    private static string joke = "yo momma";

    private string GetJoke()
    {
        lock(Foo.objectToLockOn)
        {
            return Foo.joke;
        }
    }
}

class Foo
{
    private static string joke = "yo momma";

        private string GetJoke()
        {
            string joke;

            lock(Foo.objectToLockOn)
            {
                joke = Foo.joke;
            }

            return joke;
        }
}
도움이 되었습니까?

해결책

지 않기 때문에의 코드 작성을 수정한 정적 필드 후 초기화할 필요가 없에 대한 모든 잠그고 있습니다.교체 문자열로 새로운 값이 할 필요가 없 동기화를 하지 않는 한,새로운 값의 결과에 따라 읽기의 값입니다.

정적 필드가 필요로 하는 것을 동기화,공유 참조를 수정 될 수있는 취약한 동기화 문제가 발생합니다.

class Foo
{
    private int count = 0;
    public void TrySomething()    
    {
        count++;
    }
}

수도 있다고 가정하는 두 개의 스레드를 실행하 TrySomething 방법이 허용될 수 있습니다.그러나 그것의하지 않습니다.

  1. 스레드의 값을 읽 count(0)으로 등록할 수 있도록 증가합니다.
  2. 컨텍스트 스위치!스레드 스케줄러 결정 스레드에 충분했행 시간입니다.다음 줄에서 스레드 B.
  3. 실 B 값을 읽습니다.count(0)으로 등록합니다.
  4. 실 B 증가시킵니다.
  5. 실 B 저장 결과(1)를 계산합니다.
  6. 컨텍스트 스위치 다시 A.
  7. 스레드에 다시 로드 레지스터의 값을 계산(0)에 저장됩니다.
  8. 스레드를 증가시킵니다.
  9. 스레드를 저장한 결과(1)를 계산합니다.

그렇더라도 우리는 count++,두 번의 값을 수가 그냥 갔 0~1.을 만들 수 있습니다드 thread-safe:

class Foo
{
    private int count = 0;
    private readonly object sync = new object();
    public void TrySomething()    
    {
        lock(sync)
            count++;
    }
}

지금 할 때 스레드 중단되는 실 B 할 수 없는 혼란으로 계산할 것이기 때문에 잠금 문 다음을 차단까지 스레드가 출시 동기화됩니다.

해 있는 다른 방법을 확인 증가 Int32s 및 Int64s thread-safe:

class Foo
{
    private int count = 0;
    public void TrySomething()    
    {
        System.Threading.Interlocked.Increment(ref count);
    }
}

에 관한 질문의 두 번째 부분,나는 생각한 것이지만 어느 것이 쉽게 읽고,어떤 성과 차이가 있을 것이 무시할 수 있습니다.초기 최적화는 모든 악의 뿌리,등등.

왜 스레딩드

다른 팁

를 읽거나 쓰는 32 비트 또는 작은 분야 원자에서 동작 C#.에 대한 필요가 없는 잠금에 코드를 제시하고,멀리로 나가 볼 수 있습니다.

그것은 나에게 보이는 불필요한에서 당신의 첫 번째 사례입니다.를 사용하여 정적 이니셜라이저를 초기화하는 바를 보장 스레드에 안전합니다.때문에 당신은 이제까지 값을 읽을 필요가 없을 잠급니다.이 값의 결코 변경하려고,없을 것입니다 어떤 경쟁 왜 잠금까요?

더 읽는?

내 생각에,당신은 당해 매우 열심히 노력하지 않는 정적 변수를 위치에서 그들이 할 필요가 읽기/쓰기에서 다른 스레드입니다.그들은 기본적으로 무한 모든 글로벌 변수에는 전역 변수는 거의 항상 나쁜 것은 아니다.

즉,당신을 넣어 정적 변수에 위치할 수 있습 잠금을 읽는 동안,단지의 경우-기억,또 다른 스레드에 있는 급에서 변경된 값 읽기,그리고 그것이 경우에,당신은 끝날지도 모른 손상 데이터입니다.를 읽지 않는 반드시 원자 작업하지 않는 한 당신이 그들을 지키기 위하여 잠금.와 같은 씁니다-그들은 항상 원자 작업을 하거나.

편집:으로 표시,지적에 대한 특정 프리미티브 C#읽은 항상 유념해야 합니다.하지만 조심으로 기타 데이터 유형이 있습니다.

당신이 쓰는 가치를 포인터,당신은 당신을 잠글 필요가 없기 때문하는 작업이 원자.일반적으로,당신은 잠금 시간을 필요로 하는 트랜잭션을 포함하는 적어도 두 원자 작업(를 읽거나 쓰)는 상태에 따라 변경되지 않는 간의 시작과 끝입니다.

는 말했다–나는 자바에서 땅의 모든 읽기와 쓰기의 변수는 원자 작업입니다.다른 대답이 여기 것이 좋다.그물은 다릅니다.

로"더 나은"질문에 그들이 동일한 이후 기능 범위 사용되지 않습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top