【发布时间】:2017-03-14 09:32:56
【问题描述】:
我试图在一定时间后使我的控制台应用程序崩溃(这是因为我测试了应用程序是否会在崩溃后自行启动。遵循this 教程)
我所拥有的是这段代码:
static class WebSocket
{
static int Main(string[] args)
{
Recovery.RegisterForAutostart();
Recovery.RegisterForRestart();
Test.Run();
// some more code
}
}
public static class Recovery
{
[Flags]
public enum RestartRestrictions
{
None = 0,
NotOnCrash = 1,
NotOnHang = 2,
NotOnPatch = 4,
NotOnReboot = 8
}
public delegate int RecoveryDelegate(RecoveryData parameter);
public static class ArrImports
{
[DllImport("kernel32.dll")]
public static extern void ApplicationRecoveryFinished(
bool success);
[DllImport("kernel32.dll")]
public static extern int ApplicationRecoveryInProgress(
out bool canceled);
[DllImport("kernel32.dll")]
public static extern int GetApplicationRecoveryCallback(
IntPtr processHandle,
out RecoveryDelegate recoveryCallback,
out RecoveryData parameter,
out uint pingInterval,
out uint flags);
[DllImport("KERNEL32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int GetApplicationRestartSettings(
IntPtr process,
IntPtr commandLine,
ref uint size,
out uint flags);
[DllImport("kernel32.dll")]
public static extern int RegisterApplicationRecoveryCallback(
RecoveryDelegate recoveryCallback,
RecoveryData parameter,
uint pingInterval,
uint flags);
[DllImport("kernel32.dll")]
public static extern int RegisterApplicationRestart(
[MarshalAs(UnmanagedType.BStr)] string commandLineArgs,
int flags);
[DllImport("kernel32.dll")]
public static extern int UnregisterApplicationRecoveryCallback();
[DllImport("kernel32.dll")]
public static extern int UnregisterApplicationRestart();
}
public class RecoveryData
{
string currentUser;
public RecoveryData(string who)
{
currentUser = who;
}
public string CurrentUser
{
get { return currentUser; }
}
}
// Restart after crash
public static void RegisterForRestart()
{
// Register for automatic restart if the application was terminated for any reason.
ArrImports.RegisterApplicationRestart("/restart",
(int)RestartRestrictions.None);
}
// Start app when PC starts
public static void RegisterForAutostart()
{
#if (!DEBUG)
RegistryKey key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
key.SetValue("websocket", @"c:\websocket\run.bat");
#endif
}
public static class Test
{
public static void Run()
{
crash();
}
static void crash()
{
double crashAfter = 1.5 * 60; // seconds
int secondsPassed = 0;
int waitSeconds = 1;
Console.WriteLine("\nCrash test startet, crash will occour in " + crashAfter + " seconds");
Timer timer = new Timer(
delegate (object seconds) {
secondsPassed += int.Parse(seconds.ToString());
if (secondsPassed > crashAfter)
{
Console.WriteLine("Crashing");
Environment.FailFast("Test - intentional crash."); // Error happens here
}
else
{
double timeUntilCrash = (crashAfter - secondsPassed);
Console.WriteLine("Time until crash = " + timeUntilCrash + " seconds");
}
},
waitSeconds,
TimeSpan.FromSeconds(waitSeconds),
TimeSpan.FromSeconds(waitSeconds));
}
}
当崩溃时,我会收到以下消息:
无法计算表达式,因为线程在某个点停止 垃圾收集是不可能的,可能是因为代码是 优化。
代码优化的复选框未选中。
我想这是因为它不在主线程中,如果是这种情况,我该如何返回主线程。如果不是,可能是什么原因?
【问题讨论】:
-
这听起来像是一条调试器消息,因为您在程序关闭时试图观察一些变量。我怀疑你真正的问题是计时器正在被垃圾收集。尝试将其分配给静态字段,而不是将其保存在本地堆栈变量中。
-
正如@MatthewWatson 指出的 - 您的 Timer 对象被分配给一个局部变量 timer。当 timer 在退出 crash 方法时超出范围时,没有对 Timer 对象的引用并且它可用于垃圾回收。 timer 变量需要在退出 crash 时保持在范围内,因此将其设为封闭类的字段(可能是静态的)将是一种解决方案。
-
在
crash()方法之外定义一个静态计时器,如下所示:static Timer timer;。然后在您的crash()方法中通过将Timer timer = new Timer(更改为timer = new Timer(来分配给它。 -
“何时崩溃”是什么意思?你在某处设置断点吗?您是否尝试单步执行代码? Environment.FailFast 旨在通过转储进程状态来终止进程 - 调试器可能会报告发生了 FatalExecutionEngineError - 消息中某处的错误代码为 0x80131623 - 此时您的应用程序已完全终止并且无法继续。
-
您将如何尝试重新启动您的应用程序?你期待什么样的崩溃? FailFast 适用于当应用程序处于无法依赖任何东西正常工作的状态时。
标签: c# multithreading crash