高速处理列表的多个计时器导致问题
Posted
技术标签:
【中文标题】高速处理列表的多个计时器导致问题【英文标题】:Multiple Timers treating List at high speed causes issue 【发布时间】:2020-05-27 11:00:36 【问题描述】:我正在编写一个需要通过多个计时器高速处理列表的 C# 库。 我遇到了非常不稳定的错误,我尝试删除我确定包含在 List 中的元素,但程序返回以下错误:
System.IndexOutOfRangeException : 'index was outside the bounds of the array.'
我做了一个简单的例子来重现这种行为。由于该问题的随机性,我已经大力推动 List 操作,因此它会立即抛出错误。所以这个例子是必要的“怪异”。 我在这里做了一个公开回购:Issue Example Repo
基本上,这是我正在处理的:
list = new List<DummyElement>();
for (int i = 0; i < 1000; i++)
Timer addTimer = new Timer(0.01f);
addTimer.Start();
addTimer.Elapsed += AddItem;
Timer removeTimer = new Timer(0.01f);
removeTimer.Start();
removeTimer.Elapsed += RemoveItem;
void AddItem(object source, ElapsedEventArgs e)
list.Add(new DummyElement());
void RemoveItem(object source, ElapsedEventArgs e)
int listCount = list.Count;
if (listCount > 0) // This condition is successfully passed, so there is at least one element on the list
list.RemoveAt(0); // This line throw an IndexOutOfRangeException error
我认为这是与线程相关的问题,好像列表计数在条件成功通过后发生了变化。
我对线程一无所知,我该如何处理这个问题?
【问题讨论】:
您使用的是哪种Timer
? System.Windows.Forms.Timer
? System.Timers.Timer
? System.Threading.Timer
?
我使用 System.Timers.Timer
使用System.Windows.Forms.Timer
,您不必担心线程安全问题,因为它是Tick
事件在单个线程(UI 线程)中运行。
在我的项目中找不到 System.Windows.Forms.Timer,它不是专门用于 Windows 窗体应用程序的吗?
是的,它是一个特定于 Windows 窗体的组件。
【参考方案1】:
在高达 1000 的 For 循环中 - 您正在创建大约 1000 个将项目添加到列表中的计时器和 1000 个删除第一个项目的计时器。
由于您没有使用任何同步,因此会发生以下情况:- 假设 List 中有 1 个项目,并且正在执行 2 个 RemoveItems。两者都将 listCount > 0 视为 True,然后其中一个继续并删除第 0 个索引处的项目,而另一个获得异常,因为现在没有要删除的项目。
现在我无法仅通过查看代码来提出解决方案。我还需要了解意图。
这是一个教科书生产者消费者问题,因此这里的教科书建议使用 Lock 构造:
假设您有一个类成员,例如:
private object _lockMe = new object();
void RemoveItem(object source, ElapsedEventArgs e)
lock(_lockMe)
int listCount = list.Count;
if (listCount > 0) // This condition is successfully passed, so there is at least one element on the list
list.RemoveAt(0); // This line throw an IndexOutOfRangeException error
【讨论】:
不要在lock
本身上使用lock
。这是个坏主意。
我只是在阅读关于 lock 语句的内容,它看起来使用起来非常复杂,你已经让它变得简单了!它解决了这个复制示例的问题,我将尝试将它应用到我的库中!非常感谢!
@Enigmativity 我不太明白这个参数是干什么用的?
@LePioo - lock
语句中的参数?
@LePioo - 它只需要是您持有引用的任何引用对象 - 最好是类中的私有字段。以上是关于高速处理列表的多个计时器导致问题的主要内容,如果未能解决你的问题,请参考以下文章
C# - 在需要时从多个运行的计时器中处理一个特定的计时器[关闭]
Windows高速定时器,多媒体定时器winmm.dll库的使用