在C#中,處理集合的并發操作通常需要使用線程安全的數據結構或同步機制。以下是一些建議:
使用線程安全的數據結構:
.NET框架提供了一些線程安全的數據結構,如ConcurrentQueue
、ConcurrentDictionary
、BlockingCollection
等。這些數據結構在內部實現了同步機制,可以在多線程環境下安全地使用。
例如,使用ConcurrentQueue
實現生產者-消費者模式:
ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
// 生產者線程
Task producer = Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
queue.Enqueue(i);
Console.WriteLine($"Produced: {i}");
}
});
// 消費者線程
Task consumer = Task.Run(() =>
{
while (true)
{
int item;
if (queue.TryDequeue(out item))
{
Console.WriteLine($"Consumed: {item}");
}
else
{
break;
}
}
});
Task.WaitAll(producer, consumer);
使用鎖(Lock)或同步塊(SyncLock):
如果你不想使用線程安全的數據結構,可以使用lock
關鍵字或Monitor.Enter
和Monitor.Exit
方法來保護集合的訪問。這樣可以確保在同一時間只有一個線程可以訪問集合。
例如:
object lockObject = new object();
List<int> list = new List<int>();
// 生產者線程
Task producer = Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
lock (lockObject)
{
list.Add(i);
Console.WriteLine($"Produced: {i}");
}
}
});
// 消費者線程
Task consumer = Task.Run(() =>
{
while (true)
{
lock (lockObject)
{
if (list.Count > 0)
{
int item = list[0];
list.RemoveAt(0);
Console.WriteLine($"Consumed: {item}");
}
else
{
break;
}
}
}
});
Task.WaitAll(producer, consumer);
使用SemaphoreSlim
限制并發訪問:
如果你需要限制對集合的并發訪問數量,可以使用SemaphoreSlim
類。它可以設置一個初始計數器,表示可以同時訪問集合的線程數量。
例如,限制對列表的并發訪問數量為3:
SemaphoreSlim semaphore = new SemaphoreSlim(3);
List<int> list = new List<int>();
// 生產者線程
Task[] producers = Enumerable.Range(0, 10).Select(i => Task.Run(() =>
{
semaphore.Wait();
lock (list)
{
list.Add(i);
Console.WriteLine($"Produced: {i}");
}
semaphore.Release();
})).ToArray();
// 消費者線程
Task[] consumers = Enumerable.Range(0, 10).Select(i => Task.Run(() =>
{
semaphore.Wait();
lock (list)
{
if (list.Count > 0)
{
int item = list[0];
list.RemoveAt(0);
Console.WriteLine($"Consumed: {item}");
}
}
semaphore.Release();
})).ToArray();
Task.WaitAll(producers);
Task.WaitAll(consumers);
選擇合適的同步機制取決于你的具體需求和場景。在處理集合時,務必確保線程安全以避免數據競爭和不一致問題。