2009-11-20 2 views
1

일부 프로세서 집약적 인 작업을 수행하기 위해 배경 작업자를 돌보는 것보다 클래스가 있습니다. 백그라운드 작업자는 전체 클래스에 대해 전역으로 선언 된 몇 개의 문자열을 읽습니다. 해당 문자열을 잠글 필요가 있습니까? backgroundworker는 문자열을 쓰지 않으며 클래스의 생성자에 설정된 일부 디렉토리 위치를 나타내며 생성자 다음에 클래스에 의해 거의 작성되지 않습니다 (백그라운드 작성자가 작성하지 않은 경우). 따라서 이 가능합니다. 백그라운드 작업자가 주 클래스 객체에 의해 쓰여지는 것처럼 문자열을 읽을 수는 있지만 매우 희박합니다. 하지만 두 작업 (백그라운드 작업자가 읽은 작업과 기본 클래스가 작성한 작업)이 어쨌든 문자열 리터럴의 기본 작업이 아닐까요?글로벌 문자열을 읽기 전에 잠글까요?

감사합니다, 로버트

편집 : 문자열 (즉 내 애플 리케이션에 큰 문제가되지 않을 것) 날짜 또는 아무것도에서 것에 대해 걱정하지 않는다, 내가 더 걱정 "객체가 다른 곳에서 사용 중"이라는 예외를 얻는 것에 대해.

답변

7

.NET의 문자열은 변경할 수 없습니다. 그들은 바꿀 수 없다. 참조가 완전히 다른 문자열을 가리 키지 만 문자열 자체는 변경되지 않습니다.

따라서 변경할 경우 배경 작업자가 모두 동일한 문자열을 사용하지 않을 수도 있음을 염두에 두지 않으면 괜찮을 것입니다. 예 : Worker A가 문자열을 읽었을 때 다른 것으로 바꾼다면 Worker B가 새로운 문자열을 읽습니다. 어쩌면 문제가 발생하지 않을 수도 있습니다. 그러나 문자열 자체에 액세스하는 것은 확실히 안전합니다.

documentation에서 인용 :

이 유형은 스레드에 안전하다.

ETA : 아래의 의견에 Martinho Fernandes에 의해 아주 좋은 점 : 하지에 스레드 안전 객체는 자동적으로 당신이 그들과 함께하는 모든 일뿐만 아니라 스레드 안전하다는 것을 의미한다. 그는 blog post을 써서 내게 모든 것을 다시 말하도록하는 것을 보냈다 :-)

+2

이 코드는 스레드로부터 안전하지 않습니다 :'aString [aString.Length-1]'. 문자열은 변경할 수 없기 때문에 문자열에 대한 참조가 불변이라는 것을 의미하지는 않습니다. –

+0

실제로 좋은 지적입니다. – Joey

+2

뻔뻔한 플러그 : http://devnonsense.blogspot.com/2009/11/immutable-data-is-thread-safe.html –

3

잠금을 사용하지 않으면 최악의 경우 백그라운드 관리자 중 한 명이 주 클래스 및 스레드의 관점에서 오래된 문자열 복사본을 읽는 것입니다. (질문에서) 문자열로 작업 할 때 (어떤 상황에서도) "다른 곳에서 사용중인 객체"예외가 발생하지 않습니다.

다른 대답에서 올바르게 언급했듯이 문자열은 변경할 수 없으며 만든 후에 변경할 수 없습니다. 기존 문자열에 대한 변경 사항은 투명하게 이전 문자열 개체에 영향을 미치지 않고 힙의 메모리에 새로운 문자열이 만들어집니다.

잠금을 사용하면 (성능에 미치는 영향을 측정 할 수 있음) 백그라운드 작업자가 최신 문자열을 읽을 수 있습니다.

+0

잠금 장치를 사용하면 실제로 백그라운드 스레드가 최신 상태를 유지한다는 확신을주지 못합니다. 모두 스레드 스케줄링에 달려 있습니다. – Dolphin

+1

@ 돌고래 : 스레드가 실행될 때마다 잠금으로 보호되는 데이터의 오래된 값을 얻지 못합니다. 항상 최신 (일명 최신) 값을 얻습니다. –

+1

@ 돌고래 : 잠금 구조가 적절한 메모리 장벽을 생성하므로 최신 값을 읽어야합니다. 물론 쓰는 쓰레드가 똑같은 예방책을 사용하지 않았다면 그 값이 출판되었을 것이라는 보장이 없지만 읽는 쓰레드는 그것을 알 수있는 방법이 없습니다. –

1

공유 변수를 쓰거나 수정하지 않으면 잠금을 사용할 필요가 없습니다.

0

그렇습니다. 독서와 같은 작은 작업이라면 잠금을 권하고 싶습니다. 상당히 사소한 작업이어야합니다. 스레드가 문자열을 잠근 경우 다른 잠금이 유지 된 다른 스레드를 기다리고있는 교착 상태를 인식하십시오.

+2

독서와 같은 작은 일이라면 왜 잠 가야합니까? –

0

두 개의 스레드가 동시에 값을 지정하려고 할 때만 이러한 경쟁이 발생하기 때문에 잠금이 필요하지 않습니다. .NET 문자열은 불변이므로, 결과는 결코 손상되지 않습니다. 최악의 경우, 오래된 것입니다.

1

여러 문자열 A B & C가 있습니까? 배경 작업자가 A와 B의 v3과 C의 v2를 작업하고 있다면 상관이 있습니까? 그렇다면 전체 세트의 업데이트를 둘러싼 잠금 장치가 필요합니다.

두 번째 미묘한 문제는 C#이 레지스터에서 캐시 값을 선택하거나 코드의 순서를 변경하여 스레드가 "reality"와 동일한 뷰를 보지 못할 수 있다는 것입니다. this discussion과 이에 대한 답변은 question입니다.

제 생각에는 동기화를 사용하여 눈에 띄게 올바른 코드를 작성하십시오. 이 시나리오에서 성능에 미치는 영향은 분명히 사소한 것입니다. 그렇게하면 코드 관리자는 걱정할 필요조차 없습니다. 벤치마킹에서 이것이 성능 문제라고 밝혀지면 쓰레드 안전하고 영리한 코드를 연구하면서 매우 조심해야합니다.

2

예, 읽기 및 쓰기는 문자열 변수에 대해 원자 적입니다. 변수 참조 만 변경되기 때문입니다. 문자열은 변경되지 않으므로 문자열의 내용을 수정하는 모든 연산도 문자열의 새 인스턴스를 만듭니다. 변수를 통해 스왑 아웃 된 새 인스턴스에 대한 참조입니다. 그러나 이것이 주요한 문제는 아닙니다.

주요 문제는 문자열 변수 자체의 staleness와 관련이 있습니다. 적절한 동기화 메커니즘이 없으면 한 스레드의 쓰기가 다른 스레드에서 볼 수 없습니다.

결론 ... 다른 스레드가 문자열 변수를 수정할 원격 기회가있는 경우에는 작업자 스레드와 주 스레드와의 액세스를 동기화해야합니다.

편집 : staleness는 걱정할 필요가 없으므로 잠금 장치를 사용하지 않고도 괜찮을 것입니다. 그러나 작업자 스레드가 시작되기 전에 문자열 변수를 무언가로 초기화했다고 가정합니다.