2016-11-01 3 views
1

Я пытаюсь запустить приложение консоли через определенное время (это связано с тем, что я тестирую, начнет ли приложение после сбоя. Следующее 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)); 
    } 
} 

Когда пришло время аварии я получаю сообщение:

не может оценить выражение, потому что нить останавливается в точке , где сбор мусора невозможно, возможно, потому, что код оптимизирован.

Флажок для оптимизации кода не установлен.

Я считаю, что это не в основном потоке, если это так, как я могу вернуться в основной поток. А если нет, что может быть причиной?

+2

Это звучит как сообщение отладчика из-за того, что вы пытаетесь просмотреть какую-либо переменную во время закрытия программы. Я подозреваю, что ваша настоящая проблема заключается в том, что таймер собирает мусор. Попробуйте назначить его статическому полю, а не удерживать его в локальной переменной стека. –

+0

@MatthewWatson: Это может быть глупый вопрос, но разве он не является статичным, следовательно, «static void crash()» или вы говорите о том, что статический таймер «статичный» как статический таймер таймера =? –

+2

Как отметил @MatthewWatson - ваш объект Timer назначается локальной переменной _timer_. Когда _timer_ выходит из области действия при выходе из метода _crash_, ссылки на объект Timer отсутствуют, и он доступен для сбора мусора. Переменная _timer_ должна оставаться в области при выходе из _crash_, поэтому сделать это поле включенного класса (возможно, статического) будет решением. – PaulF

ответ

1

Я создал приложение, основанное на вашем коде &, что все работает так, как ожидалось, когда приложение запускается из командной строки - только в отладчике Visual Studio перезапуск не работает.

0

Благодаря PaulF мы нашли проблему. Я тестировал в Debug режиме, запуск приложения в режиме выпуска вне Visual Studio устранил проблему. Следующие NullReferenceException были вызваны отсутствием аргументов командной строки при перезапуске.

Смежные вопросы