List. 스레드 안전 추가()
일반적으로 목록이 스레드 안전하지 않다는 것은 이해하지만, 스레드가 목록에서 다른 작업(예: 트래버스)을 수행하지 않는 경우 목록에 항목을 단순히 추가하는 것이 잘못된 것입니까?
예:
List<object> list = new List<object>();
Parallel.ForEach(transactions, tran =>
{
list.Add(new object());
});
백그라운드에서 버퍼 재할당 및 요소 복사 등 많은 작업이 수행됩니다.그 코드는 위험을 야기할 것입니다.간단히 말해서, 목록에 추가할 때 원자적 작업이 없으며, 적어도 "길이" 속성은 업데이트되어야 하며, 항목은 올바른 위치에 배치되어야 하며, (별도 변수가 있는 경우) 인덱스를 업데이트해야 합니다.여러 스레드가 서로를 짓밟을 수 있습니다.그리고 성장이 필요하다면 더 많은 일들이 진행되고 있습니다.어떤 것이 목록에 글을 쓰고 있다면 다른 어떤 것도 읽거나 글을 쓰면 안 됩니다.
.NET 4.0에서는 스레드 안전하고 잠금이 필요 없는 동시 컬렉션이 있습니다.
현재의 접근 방식은 스레드 세이프가 아닙니다. 기본적으로 데이터 변환을 수행하기 때문에 PLINQ가 더 나은 접근 방식일 수 있습니다(간단한 예이지만 결국에는 각 트랜잭션을 다른 "상태" 개체로 투영합니다).
List<object> list = transactions.AsParallel()
.Select( tran => new object())
.ToList();
다음과 같은 방법으로 문제를 해결했습니다.
ConcurrentBag<object> list = new ConcurrentBag<object>();
Parallel.ForEach(transactions, tran =>
{
list.Add(new object());
});
당신이 경우용을 사용하고 .List.add
여러 스레드에서 주문에 대해 신경쓰지 않고, 그러면 아마도 당신은 색인화 기능이 필요하지 않을 것입니다.List
사용 가능한 동시 컬렉션 중 일부를 대신 사용해야 합니다.
만약 당신이 이 충고를 무시하고 단지 한다면,add
당신은 만들 수 있습니다.add
스레드는 안전하지만 다음과 같이 예측할 수 없는 순서로:
private Object someListLock = new Object(); // only once
...
lock (someListLock)
{
someList.Add(item);
}
이 예측 한 순서를 , 을 할 수 하지 않을 가능성이 .someList[i]
.
그것은 무리한 부탁이 아닙니다.다른 방법과 함께 스레드 안전 문제를 일으킬 수 있는 방법이 호출된 유일한 방법인 경우 안전한 경우가 있습니다.
그러나 리플렉터에 표시된 코드를 고려할 때 이는 분명히 해당되지 않습니다.
public void Add(T item)
{
if (this._size == this._items.Length)
{
this.EnsureCapacity(this._size + 1);
}
this._items[this._size++] = item;
this._version++;
}
라 할지라도EnsureCapacity
그 자체로 스레드 세이프(그리고 그것은 매우 확실하지 않음)였으며, 증분 연산자에 대한 동시 호출이 오서링을 유발할 가능성을 고려할 때 위의 코드는 스레드 세이프가 아닐 것이 분명합니다.
잠금, ConcurrentList 사용 또는 여러 스레드가 작업을 마친 후 여러 스레드가 쓰는 장소에서 잠금이 없는 대기열을 사용하여 직접 또는 목록을 채우는 방식으로 읽습니다(여기서는 단일 스레드 읽기에 이은 여러 동시 쓰기가 패턴이라고 가정합니다).그렇지 않다면, 나는 그 상황이 어떤지 볼 수 없습니다.Add
는 호출된 유일한 방법입니다.)
이렇게 하면 목록이 배열 위에 작성되어 스레드 안전하지 않기 때문에 스레드 위치에 따라 인덱스 범위를 벗어나는 예외가 발생하거나 다른 값을 재정의하는 일부 값이 발생할 수 있습니다.기본적으로, 하지 마세요.
여러 가지 잠재적인 문제가 있습니다.그냥 하지 마세요.스레드 세이프 컬렉션이 필요한 경우 잠금 장치를 사용하거나 시스템 중 하나를 사용합니다.컬렉션.동시 컬렉션입니다.
스레드가 목록에서 다른 작업을 수행하지 않는 경우 단순히 항목을 목록에 추가하는 것이 잘못된 것입니까?
간단한 대답: 네.
긴 답변: 아래 프로그램을 실행합니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
class Program
{
readonly List<int> l = new List<int>();
const int amount = 1000;
int toFinish = amount;
readonly AutoResetEvent are = new AutoResetEvent(false);
static void Main()
{
new Program().Run();
}
void Run()
{
for (int i = 0; i < amount; i++)
new Thread(AddTol).Start(i);
are.WaitOne();
if (l.Count != amount ||
l.Distinct().Count() != amount ||
l.Min() < 0 ||
l.Max() >= amount)
throw new Exception("omg corrupted data");
Console.WriteLine("All good");
Console.ReadKey();
}
void AddTol(object o)
{
// uncomment to fix
// lock (l)
l.Add((int)o);
int i = Interlocked.Decrement(ref toFinish);
if (i == 0)
are.Set();
}
}
다른 사람들이 이미 말했듯이, 당신은 당신은 당신의 웹사이트에서 동시 수집을 사용할 수 있습니다.System.Collections.Concurrent
네임스페이스입니다.이 중 하나를 사용할 수 있는 경우 이 방법이 좋습니다.
하지만 만약 당신이 단지 동기화된 목록을 정말 원한다면, 당신은 그것을 볼 수 있습니다.SynchronizedCollection<T>
-클래스 인System.Collections.Generic
.
시스템을 포함해야 했습니다.서비스 모델 어셈블리, 이것이 제가 그것을 그렇게 좋아하지 않는 이유이기도 합니다.하지만 가끔 사용합니다.
다른 스레드에 요소를 추가하는 것도 스레드 안전하지 않습니다.
C# 4.0에는 동시 컬렉션이 있습니다(http://jiezhu0815.blogspot.com/2010/08/c-40-feature-1-concurrent-collections.html) 참조).
언급URL : https://stackoverflow.com/questions/5589315/list-add-thread-safety
'IT' 카테고리의 다른 글
Windows 10에서 Conda 명령이 인식되지 않음 (0) | 2023.05.23 |
---|---|
아포스트로피(단일 따옴표)가 포함된 값을 삽입하는 방법은 무엇입니까? (0) | 2023.05.23 |
로드된 jQuery 버전을 확인하는 방법은 무엇입니까? (0) | 2023.05.23 |
AdMob에 응용 프로그램을 넣은 후 "라이브러리를 찾을 수 없습니다" 오류가 발생 (0) | 2023.05.23 |
원격 마스터를 로컬 분기에 병합하는 방법 (0) | 2023.05.23 |