gpt4 book ai didi

c# - 使用锁并不能阻止 Collection 被修改;枚举操作可能无法执行

转载 作者:行者123 更新时间:2023-11-30 19:55:12 25 4
gpt4 key购买 nike

这个问题已经被问过很多次了,但这是一个特例。

public class JobStatusMonitor
{
private static List<Job> _runningJobs = new List<Job>();
private static object myLock = new object();

public static void AddJob(GPSJob input)
{
lock (myLock)
_runningJobs.Add(input);
}

public static void Start(int pollInterval)
{
while (true)
{
var removeJobs = new List<GPSJob>();
lock (myLock)
{
foreach (var job in _runningJobs)
{
if (job.IsComplete())
{
removeJobs.Add(job);
}
}
}

foreach (var job in removeJobs)
{
_runningJobs.Remove(job);
}

System.Threading.Thread.Sleep(pollInterval);
}
}
}

列表 _runningJobs 是私有(private)的,因此除非使用 AddJob 方法,否则此类之外的任何人都不能修改它。 AddJob 方法使用与 foreach 循环相同的锁,因此它在迭代时不应该能够修改集合。

我对应该发生的事情的理解是 Start(5000) 被调用,列表中没有任何内容,所以它跳到 Thread.Sleep()。后台进程将作业添加到列表中。 while 循环返回到 foreach 循环并应用锁。在遍历列表时,任何其他试图添加到集合的线程都将等待直到迭代完成。一旦迭代完成,这些线程中的每一个都将添加它们的作业,即使有许多线程试图添加作业,锁也不会导致竞争条件。

实际发生的是在该线程休眠时添加的任何作业都已成功添加。尽管有锁,但在此列表迭代时添加的作业不会等待迭代完成。

为什么锁不能防止这个错误?

编辑:复制到锁内的新列表可消除错误。

public class JobStatusMonitor
{
private static List<Job> _runningJobs = new List<Job>();
private static object myLock = new object();

public static void AddJob(GPSJob input)
{
lock (myLock)
{
_runningJobs.Add(input);
}
}

public static void Start(int pollInterval)
{
while (true)
{

lock (myLock)
{
var completeJobs = _runningJobs.Where(job => job.IsComplete()).ToList();
foreach (var job in completeJobs)
{
_runningJobs.Remove(job);
job.TaskCompletionSource.SetResult(null);
}
}

System.Threading.Thread.Sleep(pollInterval);
}
}
}

最佳答案

@Philipe 发现了这个问题,您正在修改锁外的列表。您应该让所有修改调用都受到锁的保护。

为简化起见,您可以只计算新的未完成作业列表并与锁内的当前作业列表交换。类似的东西:

lock(myLock) {
var newRunningJobs = _runningJob.Where(j => !Job.IsComplete(j)).ToList();
_runningJob = newRunningJobs;
}

关于c# - 使用锁并不能阻止 Collection 被修改;枚举操作可能无法执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38205013/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com