我有一个每秒触发的计时器事件。有时当我退出程序时(在VS调试器中),它告诉我事件线程正在尝试访问不再存在的对象(因为主线程已经结束)。我在退出(UpdateTime.aTimer.Enabled = false;
)之前尝试禁用该事件。这减少了此问题发生的次数,但有时仍会发生,因为事件会在我禁用之前触发。
我问第二个问题,因为我没有引用事件线程,所以我不知道如何告诉它停止或等待它完成。
编辑:更多背景。这是一个Winform。
另外,我没有明确创建一个帖子。我的理解是自动创建一个线程来处理事件。
创建计时器:
public static void Update(){
System.Timers.Timer aTimer = new System.Timers.Timer(1000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Enabled = true;
}
事件处理程序:
private static void OnTimedEvent(object source,ElapsedEventArgs e) {
Form1obj.updateLabel(String.Format("{0}", DateTime.Now.Second),Label1);
}
关闭程序处理程序:
private void Form1_FormClosing(object sender,FormClosingEventArgs e) {
aTimer.Enabled = false;
}
答案 0 :(得分:3)
严重的问题?可能不是,但我不认为需要修复问题需要认真解决。例如,警告应被视为编译中的错误。此外,如果这是一个发送给客户的应用程序,在关机时显示丑陋的错误不是很专业。
如何解决这个问题取决于你如何设置线程(“事件线程”没有提供有关机制的足够信息)。一个简单的方法可能是在应用程序关闭时将主线程暂停一段时间,直到线程全部返回。您还必须在此期间停止发布新线程。
另一种可能的解决方案是处理线程的创建方式,以便关闭触发它们的进程。我想到了像ThreadPool这样的概念。在某些情况下,明确地确保线程是后台线程也可以提供帮助。
简短的回答是,如果没有您在代码中所做的事情的背景,没有人能够为您提供“这将解决您的问题”的答案。
增加:
有一些“快速,向下和肮脏”的方法来处理这个问题。没有时间进行全面分析,所以看看它们是否有效。
我要考虑的第一件事是添加一个安全网,以便在关机状态下不更新标签。这与其他任何事情无关,因为这是你的错误发生的地方。我不认为“主线程不存在”是问题的核心,而是这一行:
Form1obj.updateLabel(String.Format("{0}", DateTime.Now.Second),Label1);
如何更新不再存在的内容?是的,它在主线上,所以技术上......
简单的等待就像:
private void Form1_FormClosing(object sender,FormClosingEventArgs e)
{
aTimer.Enabled = false;
Thread.Sleep(5000);
}
隐藏表单也不错,所以用户看不到这个?
如果您想使用更多“类似COM的方法”,您可以添加一个计数器。 Update()的增量(当事件被触发时)和OnTimedEvent()的减量。确保在更换计数器时锁定计数器,这样就不会在同一毫秒内更换两个螺纹。然后,您可以等到计数器为0以完成表单关闭或应用程序卸载。
再次,这些是快速,向下和肮脏的方法,但它们可以帮助您避免错误。我相信有更多时间的人可以提出更优雅的解决方案。
答案 1 :(得分:1)
您可以关闭窗口as suggested in MSDN - 当您在关机处理期间将计时器设置为禁用时,设置一个标记,您的Elapsed
事件处理程序可以检查以确定不再需要其他工作。< / p>
经过事件后可能会发生 已调用Dispose或Stop方法 或者在Enabled属性之后 设置为false,因为信号来 始终提高Elapsed事件 排队等待在线程池上执行 线。解决这场比赛的一种方法 条件 是设置一个告诉事件的标志 Elapsed事件的处理程序 忽略后续事件。
答案 2 :(得分:0)
如果问题严重与否,很难给出一个普遍的问题,这取决于计时器在做什么。它是什么样的计时器?一个系统。如何处理一个或一个UI计时器?
如果可能的话,尝试并重构您的代码,以便您可以告诉计时器停止触发,只是为了不让用户混淆错误消息。它可以像共享变量一样简单,也可以(最好)使用CancellationToken