최근까지, 나는 인덱서를 통해 List<T>
의 요소를 설정하면 다음과 같은 상황에서 안전 스레드가 있다는 가정하에 있었다. 배열C# 목록 <T> 인덱서 스레드 안전
// Assumes destination.Count >= source.Count
static void Function<T,U>(List<T> source, Func<T,U> converter, List<U> destination)
{
Parallel.ForEach(Partitioner.Create(0, source.Count), range =>
{
for(int i = range.Item1; i < range.Item2; i++)
{
destination[i] = converter(source[i]);
}
});
}
List<T>
저장 소자 이후 내부적 리사이징 필요로하지 않아야 인덱스 한 설정이 믿음 합리적인 도약 같았다. 그러나 .NET 코어에서 implementation이 List<T>
인 것을 보면 인덱서의 설정자가 일부 내부 상태를 수정 한 것처럼 보입니다 (아래 참조).
// Sets or Gets the element at the given index.
public T this[int index]
{
get
{
// Following trick can reduce the range check by one
if ((uint)index >= (uint)_size)
{
ThrowHelper.ThrowArgumentOutOfRange_IndexException();
}
Contract.EndContractBlock();
return _items[index];
}
set
{
if ((uint)index >= (uint)_size)
{
ThrowHelper.ThrowArgumentOutOfRange_IndexException();
}
Contract.EndContractBlock();
_items[index] = value;
_version++;
}
}
그래서 나는 List<T>
는 스레드로부터 안전하지 않습니다 것을 각 스레드는 컬렉션의 고유 한 부분에서 요소를 설정/얻고 경우에도 가정해야합니까?
([당신이 부르는 일이 무엇입니까? "스레드로부터 안전합니다"] https://blogs.msdn.microsoft.com/ericlippert/2009/10/19/what-is-this-thing-you-call-thread -안전한/). 가장 먼저해야 할 일은 안전이 필요한 것을 파악하는 것입니다. 보고있는 코드에 관해서는 스레드로부터 안전하다고는 말할 수 없습니다. 그리고 실제로는 thread-safe로서 문서화되지 않은 것을 가정해서는 안됩니다. 그러나,'_version' 필드는 당신이 신경 쓸 필요가없는 구현 세부 사항에 사용됩니다. 안전하지 못하다는 사실이 당신에게 중요하지 않을 수도 있습니다. –
당신이 스레드 안전을 원하는 경우에, 당신이있어 비록 [스레드 안전 컬렉션] (https://msdn.microsoft.com/en-us/library/dd997305 (V = vs.110)에서 .aspx) – Timo
를 살펴 실제로 이것을 요구하지는 않지만 병렬 루프 내에서 상태를 수정하지 않는 것이 좋습니다. 상황이'converter'가 장기 실행 연산 인 경우에는'Parallel'을 사용하여 결과를 계산 한 다음 하나의 스레드로 결과를 할당하는 것이 가장 좋습니다. 이것을보십시오 :'static List Function (소스 코드 소스, Func 변환기) {return source.AsParallel(). (변환기 =) 변환기를 선택하십시오. }' –
Enigmativity