diff --git a/Ink Canvas/App.xaml.cs b/Ink Canvas/App.xaml.cs index 6329aa4f..b85ccfdd 100644 --- a/Ink Canvas/App.xaml.cs +++ b/Ink Canvas/App.xaml.cs @@ -475,7 +475,7 @@ public static void ShowSplashScreen() LogHelper.WriteLogToFile("启动画面对象创建成功,准备显示..."); _splashScreen.Show(); _isSplashScreenShown = true; - splashScreenStartTime = DateTime.Now; + Interlocked.Exchange(ref splashScreenStartTimeTicksUtc, DateTime.UtcNow.Ticks); LogHelper.WriteLogToFile("启动画面已显示"); } catch (Exception ex) @@ -694,7 +694,7 @@ private void App_DispatcherUnhandledException(object sender, DispatcherUnhandled async void App_Startup(object sender, StartupEventArgs e) { appStartTime = DateTime.Now; - appStartupStartTime = DateTime.Now; + Interlocked.Exchange(ref appStartupStartTimeTicksUtc, DateTime.UtcNow.Ticks); // 根据设置决定是否显示启动画面 if (ShouldShowSplashScreen() && !IsLaunchByFileOrUri(e.Args)) @@ -1078,7 +1078,12 @@ async void App_Startup(object sender, StartupEventArgs e) mainWindow.Loaded += (s, args) => { isStartupComplete = true; - startupCompleteHeartbeat = DateTime.Now; + var startupCompleteHeartbeat = DateTime.UtcNow; + Interlocked.Exchange(ref startupCompleteHeartbeatTicksUtc, startupCompleteHeartbeat.Ticks); + Interlocked.Exchange(ref lastHeartbeatTicksUtc, startupCompleteHeartbeat.Ticks); + + var splashScreenStartTime = ReadUtcTicks(ref splashScreenStartTimeTicksUtc); + var appStartupStartTime = ReadUtcTicks(ref appStartupStartTimeTicksUtc); if (_isSplashScreenShown && splashScreenStartTime != DateTime.MinValue) { LogHelper.WriteLogToFile($"启动完成心跳已记录,启动画面显示时长: {(startupCompleteHeartbeat - splashScreenStartTime).TotalSeconds:F2}秒"); @@ -1189,12 +1194,19 @@ public enum CrashActionType // 心跳相关 private static DispatcherTimer heartbeatTimer; - private static DateTime lastHeartbeat = DateTime.Now; + private static long lastHeartbeatTicksUtc = DateTime.UtcNow.Ticks; private static Timer watchdogTimer; private static bool isStartupComplete = false; - private static DateTime startupCompleteHeartbeat = DateTime.MinValue; - private static DateTime splashScreenStartTime = DateTime.MinValue; - private static DateTime appStartupStartTime = DateTime.MinValue; + private static long startupCompleteHeartbeatTicksUtc = DateTime.MinValue.Ticks; + private static long splashScreenStartTimeTicksUtc = DateTime.MinValue.Ticks; + private static long appStartupStartTimeTicksUtc = DateTime.MinValue.Ticks; + private static readonly TimeSpan StartupCompleteGracePeriod = TimeSpan.FromSeconds(30); + + private static DateTime ReadUtcTicks(ref long ticks) + { + long value = Interlocked.Read(ref ticks); + return value == DateTime.MinValue.Ticks ? DateTime.MinValue : new DateTime(value, DateTimeKind.Utc); + } /// /// 启动并管理应用的心跳与守护检查定时器,监测启动阶段与主线程是否无响应,并在符合配置的情况下尝试静默重启应用。 @@ -1213,7 +1225,7 @@ private void StartHeartbeatMonitor() { Interval = TimeSpan.FromSeconds(1) }; - heartbeatTimer.Tick += (_, __) => lastHeartbeat = DateTime.Now; + heartbeatTimer.Tick += (_, __) => Interlocked.Exchange(ref lastHeartbeatTicksUtc, DateTime.UtcNow.Ticks); heartbeatTimer.Start(); watchdogTimer = new Timer(_ => @@ -1221,12 +1233,16 @@ private void StartHeartbeatMonitor() if (IsOobeShowing) return; + DateTime now = DateTime.UtcNow; + DateTime appStartupStartTime = ReadUtcTicks(ref appStartupStartTimeTicksUtc); + if (!isStartupComplete && appStartupStartTime != DateTime.MinValue) { + DateTime splashScreenStartTime = ReadUtcTicks(ref splashScreenStartTimeTicksUtc); DateTime startTime = _isSplashScreenShown && splashScreenStartTime != DateTime.MinValue ? splashScreenStartTime : appStartupStartTime; - TimeSpan elapsedSinceStart = DateTime.Now - startTime; + TimeSpan elapsedSinceStart = now - startTime; if (elapsedSinceStart.TotalMinutes >= 2) { string timeType = _isSplashScreenShown ? "启动画面已显示" : "应用启动开始"; @@ -1252,8 +1268,13 @@ private void StartHeartbeatMonitor() return; } } - if (isStartupComplete && (DateTime.Now - lastHeartbeat).TotalSeconds > 10) + DateTime lastHeartbeat = ReadUtcTicks(ref lastHeartbeatTicksUtc); + if (isStartupComplete && (now - lastHeartbeat).TotalSeconds > 10) { + DateTime startupCompleteHeartbeat = ReadUtcTicks(ref startupCompleteHeartbeatTicksUtc); + if (startupCompleteHeartbeat != DateTime.MinValue && (now - startupCompleteHeartbeat) < StartupCompleteGracePeriod) + return; + LogHelper.NewLog("检测到主线程无响应,自动重启。"); SyncCrashActionFromSettings(); if (CrashAction == CrashActionType.SilentRestart)