【问题标题】:Application won't crash on purpose while in another thread应用程序在另一个线程中不会故意崩溃
【发布时间】: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


【解决方案1】:

我根据您的代码创建了一个应用程序,发现从命令行运行该应用程序时一切都按预期运行 - 只有在 Visual Studio 调试器中重启不起作用。

【讨论】:

    【解决方案2】:

    感谢PaulF,我们找到了问题所在。我在Debug 模式下进行测试,在 Visual Studio 之外以发布模式运行应用程序解决了这个问题。以下NullReferenceException 是由于重启时缺少命令行参数引起的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-30
      相关资源
      最近更新 更多