Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- App.xaml стандартный.
- App.xaml.cs:
- using System;
- using System.Windows;
- namespace HangApp
- {
- public partial class App : Application
- {
- FreezeWatcher fw;
- protected override void OnStartup(StartupEventArgs e)
- {
- base.OnStartup(e);
- fw = new FreezeWatcher(TimeSpan.FromSeconds(5));
- fw.MainThreadHangs += OnHang;
- }
- void OnHang(object sender, EventArgs e)
- {
- MessageBox.Show("Вы зависли, ха-ха! Прощайте.", "Ашипка");
- Environment.Exit(1);
- }
- protected override void OnExit(ExitEventArgs e)
- {
- fw.MainThreadHangs -= OnHang;
- fw.Dispose();
- base.OnExit(e);
- }
- }
- }
- FreezeWatcher.cs:
- using System;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Windows;
- using Microsoft.Win32;
- namespace HangApp
- {
- public class FreezeWatcher : IDisposable
- {
- public FreezeWatcher(TimeSpan? pingTimeout = null, TimeSpan? checkTimeout = null)
- {
- if (!Application.Current.Dispatcher.CheckAccess())
- throw new InvalidOperationException("Must be constructed in main application thread");
- if (pingTimeout != null)
- {
- this.pingTimeout = pingTimeout.Value;
- this.checkTimeout = checkTimeout ?? pingTimeout.Value;
- }
- mainTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
- mainTask = Task.Run(Run);
- }
- async Task Run()
- {
- try
- {
- await LoopChecks(cancellationTokenSource.Token);
- }
- catch (OperationCanceledException)
- {
- /* do nothing, cancellation is expected */
- }
- }
- async Task LoopChecks(CancellationToken ct)
- {
- try
- {
- SystemEvents.PowerModeChanged += OnPowerModeChanged;
- while (true)
- {
- await Task.Delay(checkTimeout, ct);
- PowerStateChanged = false;
- var pingSuccess = await Check(ct);
- if (!pingSuccess && !PowerStateChanged)
- {
- OnHang();
- await Unhung(ct);
- OnUnhang();
- }
- }
- }
- finally
- {
- SystemEvents.PowerModeChanged -= OnPowerModeChanged;
- }
- }
- void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
- {
- PowerStateChanged = true;
- }
- async Task<bool> Check(CancellationToken ct)
- {
- var ping = PingMain(ct);
- var delay = Task.Delay(pingTimeout, ct);
- var succeeded = (await Task.WhenAny(ping, delay)) == ping;
- ct.ThrowIfCancellationRequested();
- return succeeded;
- }
- Task Unhung(CancellationToken ct)
- {
- return PingMain(ct);
- }
- Task PingMain(CancellationToken ct)
- {
- return Task.Factory.StartNew(
- () => { /* nothing */ },
- ct,
- TaskCreationOptions.PreferFairness,
- mainTaskScheduler);
- }
- void OnHang() => MainThreadHangs?.Invoke(this, new EventArgs());
- void OnUnhang() => MainThreadUnhangs?.Invoke(this, new EventArgs());
- public void Dispose()
- {
- if (isDisposed)
- return;
- isDisposed = true;
- cancellationTokenSource.Cancel();
- mainTask.Wait();
- }
- public event EventHandler<EventArgs> MainThreadHangs;
- public event EventHandler<EventArgs> MainThreadUnhangs;
- TaskScheduler mainTaskScheduler;
- TimeSpan pingTimeout = TimeSpan.FromSeconds(30);
- TimeSpan checkTimeout = TimeSpan.FromSeconds(30);
- Task mainTask;
- CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
- bool isDisposed = false;
- object powerStateMutex = new object();
- bool powerStateChanged = false;
- bool PowerStateChanged
- {
- get { lock (powerStateMutex) return powerStateChanged; }
- set { lock (powerStateMutex) powerStateChanged = value; }
- }
- }
- }
- MainWindow.xaml:
- <Window x:Class="HangApp.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:HangApp"
- mc:Ignorable="d"
- Title="Test" Height="350" Width="525">
- <Grid>
- <Button HorizontalAlignment="Center" VerticalAlignment="Center" Width="100" Click="DoHang">Freeze</Button>
- </Grid>
- </Window>
- MainWindow.xaml.cs:
- using System.Windows;
- namespace HangApp
- {
- public partial class MainWindow : Window
- {
- public MainWindow()
- {
- InitializeComponent();
- }
- void DoHang(object sender, RoutedEventArgs e)
- {
- new System.Threading.Semaphore(0, 1).WaitOne();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement