我使用的是带有Compact Framework 2 SP2的C#。
该设备的操作系统设置为启动我的应用程序,让我们将该应用程序称为"Loader.exe">
Loader就是这样:一个单一的、简单的表单,在整个加载过程中显示状态消息,如果需要的话(外行的术语是存在错误和异常消息,或"启动应用程序[xyz]"),以及一个在后台运行的状态机,同时显示一个基本的全屏表单。
因此Loader的表单构造函数在非常的末尾有以下内容:
try
{
label1.Text = "Starting GUI Init Thread..."; //debug only message
System.Threading.Timer guiInit = new System.Threading.Timer(
RunStateMachine, null, 2000, System.Threading.Timeout.Infinite
);
//callback: RunStateMachine, null argument
//initial callback is 2000ms from this point, and doesn't run again.
}
catch (Exception ex1)
{
label1.Text = "GUI Init Error 2";
Failure_Label.Text = ex1.Message;
}
"RunStateMachine"在不同于UI的线程上工作,允许窗体显示,并且每当RunStateMachine需要与窗体交互时,例如更新消息时,我都会调用一个函数,该函数使用if(this.InvokeRequired){this.Invoke(…);}else{…}
那么,我的问题是什么
偶尔,我的程序会挂起,这是因为计时器没有触发回调。我在上面的try块中添加了调试消息,以及许多其他地方告诉我它挂在哪里,包括在"RunStateMachine"的最开始时的一条消息。最终,我的程序挂在了消息"Starting GUI Init Thread…"上
这告诉我线程计时器没有运行我需要的一个时间。
我的理论是,它在计时器触发回调之前被垃圾收集。这意味着,如果计时器是全局的,然后在我到达RunStateMachine时显式处理,它将完美运行。。。但我不想认为我解决了这个问题,只是发现一个月后这个问题会间歇性地出现。
想法?
我的理论是,它在计时器之前被垃圾收集触发回调。这意味着如果计时器是全局的,并且然后当我到达RunStateMachine时显式地处理,它将完美运行。。。但我不想认为我解决了它只是为了找到一个月后这种情况会间歇性出现。
看起来您需要确认这是您的问题是的,这就是问题所在
计时器存储在一个局部变量中,该变量永远不会再使用。这使其有资格获得GC。计时器的GC’ing导致最终确定,导致计时器被禁用。
我建议您将计时器存储在窗体类的实例字段中,并在回调启动后将其删除。