2010-07-28 2 views
2

나는 몇 개의 arraylists가있는 클래스가 있습니다.스레딩 된 응용 프로그램에서 C# Volatile 키워드 사용

내 기본 클래스가이 클래스의 새 인스턴스를 만듭니다. 나의 메인 클래스는 클래스에 arraylists를 추가하고 제거하는 적어도 2 개의 쓰레드를 가진다. 순간 모든 것이 제대로 실행되고 있지만에서 arraylists 내 클래스를 선언하는 것이 안전 할 것이다 경우 난 그냥 궁금해서 그와 같은 휘발성 예를 들어/

현재
private volatile myclass; 
myclass = new myclass(); 
...... 
myclass.Add(...) 
myclass.Clear(..) 
+1

휘발성 필드에만 적용 가능 – Kimi

+0

왜 휘발성으로 만들고 싶습니까? 애플리케이션에 가치를 추가 할 예정입니까? – Shekhar

+1

이제 자신에게 질문하고 동의하십시오. 귀하의 질문 중 거의 90 %가 답변을드립니다. – Incognito

답변

4

volatile 키워드를 사용해도이 예에서는 코드가 스레드로부터 안전하지 않습니다. 휘발성 키워드는 일반적으로 변수 값 (예 : 클래스 필드)을 읽거나 쓸 때 해당 변수의 최신 값이 주 메모리에서 읽히거나 캐시에서 읽지 않고 주 메모리에 직접 쓰게하는 데 사용됩니다 (예 : CPU 레지스터)를 포함한다. volatile 키워드는 "이 공유 필드에서 캐싱 최적화를 사용하지 마십시오"라고 말하는 방법이며 스레드가 필드의 로컬 복사본을 사용하여 서로의 업데이트를 볼 수없는 문제를 제거합니다.

myclass의 값이 실제로 업데이트되지 않습니다 (즉, myclass를 다시 할당하지 않음). 휘발성이 유용하지 않으며 실제로 스레드를 만들고 싶은 myclass 변수의 업데이트가 아닙니다 이 경우 어쨌든 안전합니다.

실제 클래스를 스레드로부터 안전하게 업데이트하려면 "추가"및 "지우기"주위에 "잠금"을 사용하는 것이 간단합니다. 이렇게하면 한 번에 하나의 스레드 만 myclass의 내부 상태를 업데이트하는 이러한 작업을 수행 할 수 있으므로 병렬로 수행하면 안됩니다.

private readonly object syncObj = new object(); 
private readonly myclass = new myclass(); 
...... 

lock (syncObj) 
{ 
    myclass.Add(...) 
} 

lock (syncObj) 
{ 
    myclass.Clear(..) 
} 

당신도 그런 경우가 없지만, "추가"로 업데이트되는 상태를 읽는 코드를 주위에 잠금 추가해야 다음과 같이

잠금을 사용할 수 있습니다 예제 코드에 나타납니다.

컬렉션에 추가 할 때 왜 잠금이 필요한지 멀티 스레드 코드를 처음 작성할 때 명확하지 않을 수 있습니다. List 또는 ArrayList를 예로 들면, 내부적으로 이러한 콜렉션이 배열을 보조 저장소로 사용하므로 동적으로 "Array"를 확장합니다 (즉, 더 큰 새로운 Array를 만들고 이전 내용을 복사하여). Add가 호출되면 용량이 충족됩니다. 이것은 모두 내부적으로 발생하며이 Array 및 변수의 현재 크기 (실제 배열의 길이가 더 클 수도 있음)와 같은 변수를 유지 관리해야합니다. 따라서 내부 배열을 확장해야하는 경우 컬렉션에 추가하는 과정에 여러 단계가 필요할 수 있습니다. 안전하지 않은 방식으로 여러 스레드를 사용하는 경우 여러 스레드가 추가로 인해 간접적으로 성장을 일으켜 다른 모든 업데이트를 트램프 할 수 있습니다.다중 스레드 문제뿐만 아니라 동시에 다른 스레드가 컬렉션을 읽는 중일 수 있으며 내부 상태가 변경되는 중이라는 문제가 있습니다. 잠금을 사용하면 이러한 작업을 다른 스레드로부터의 간섭없이 수행 할 수 있습니다.

+0

말하거나 잠그는 것처럼 개체 주위에 자물쇠를 두는 것이 더 낫습니다 (이). 잠금이 사용되고 다른 스레드가 잠금을 사용하려고하면 어떻게됩니까? 기다리고있을 뿐인가? – Jon

+0

@ 존 ** 질문 ** 1 : "this"는 해당 클래스 인스턴스에 대한 참조를 가진 사람 (클래스 외부의 스레드)이 볼 수 있으므로 "this"가 아닌 private 잠금 변수를 잠그는 것이 가장 좋습니다 사실 동일한 클래스에 대한 참조를 잠급니다. 이는 "this"를 사용하여 의도하지 않은 결과입니다. –

+0

@Jon ** 질문 ** 2 : 스레드가 일시 중지 된 상태에서 사용 중이던 잠금 섹션 (잠금 경합이라고 함)을 입력하려고 시도하면 잠금이 해제 될 때 깨어납니다. 대기중인 스레드가 여러 개인 경우 하나의 스레드 만 성공하고 나머지는 다시 일시 중단됩니다. 잠금 장치가 경합하지 않는 경우 (즉, 사용 중일 때) 실제 잠금 확인 및 가져 오기는 매우 빠릅니다. 코드를 잠금 범위 내에서 효율적으로 유지하고 멀티 스레드, 정확성 및 가독성이 중요한 경우. 지옥 최적화를 시도하기 전에 정확성과 단위 테스트를 실시하십시오. –

2

, 코드가 잘못; volatile 키워드를 추가해도 문제가 해결되지 않습니다. 동기화를 추가하지 않고 스레드간에 .NET 클래스를 사용하는 것은 안전하지 않습니다.

코드 구조에 대해 자세히 알지 못해서 직접적인 조언을하기가 어렵습니다. 첫 번째 단계는 목록 객체에 대한 모든 액세스를 중심으로 lock 키워드를 사용하는 것입니다. 그러나 코드에서 여전히 여러 스레드에서 작동하지 않는 가정이있을 수 있습니다.

lock 키워드를 올바른 위치에 가져올 필요가없는 다중 스레드 액세스에 대해 이미 안전한 컬렉션 클래스를 사용할 수도 있지만 오류는 여전히 발생할 수 있습니다.

코드를 더 게시 할 수 있습니까? 그렇게하면 스레드를 안전하게 유지하는 방법에 대해보다 구체적인 제안을 할 수 있습니다.

+0

어떤 컬렉션이 스레드로부터 안전한지 아십니까? – Jon

+0

이 페이지는 좋은 설명을 제공합니다. http://msdn.microsoft.com/en-us/library/573ths2x(VS.90).aspx. 그러나 스레드 안전 컬렉션을 사용하면 문제가 해결되지 않을 수도 있습니다. 귀하의 코드가 광산과 같은 것이면 그것은 안전하지 않은 방식으로 항목 자체를 사용하여 작업 할 것입니다. –

+0

감사합니다. 본질적으로 클래스에는 몇 개의 arraylists가 있습니다. 그런 다음 클래스에 추가/삭제/지우기/찾기 명령을 작성하여 관련 arraylist에게 전달하고 해당 작업을 수행합니다. 그러나이 클래스의 인스턴스는 최대 2 개의 스레드에서 추가/제거를 호출 할 수 있습니다. 클래스를 사용할 때마다이 클래스 인스턴스를 잠글 필요가있는 것 같습니다. – Jon

관련 문제