c# – Determining the hover point of a C # program

Question:

There is a program that rarely freezes. The program is executed on remote machines, and there is no way to start the debugger. Running an external profiler is more realistic, but also fraught with enormous difficulties. How can you determine the hang-point of the program without resorting to a profiler?

The option "detailed logging of the program's operation to the file system" is not suitable. The program consists of about 20 thousand lines of code, and rarely hangs.

Tried Process Explorer, but it works very strangely (or I didn't figure it out). If you manage to "catch" a thread that has entered an infinite loop, then it is quite possible to look at its stack. But this flow quickly disappears (either in PE, or the environment really kills it).

The option of creating another application, a monitor application, is quite acceptable. If you can somehow create a process dump or get information about the threads of this process, then it would be great. If there is a ready-made tool, then even better.

Answer:

I used this idea:

  1. Find out if there is a freeze. For this, a background thread is created, which from time to time tries to execute an empty callback in the main thread, and if the execution takes a suspiciously long time , a reaction is triggered:

     async Task LoopChecks(CancellationToken ct) { try { // исключить реакцию, если мы побывали в Sleep/Hibernate 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; } } 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 PingMain(CancellationToken ct) { return Task.Factory.StartNew( () => { /* nothing */ }, ct, TaskCreationOptions.PreferFairness, mainTaskScheduler); } void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e) { PowerStateChanged = true; }

    The PowerStateChanged property must, of course, be protected inside the lock , since it will change from some unknown thread inside OnPowerModeChanged .

  2. In case a hang is detected, a lot of things happened. The user was shown (in the new UI thread, of course) a dialog about the program's hangup (which was automatically hidden when hanging up). An external application was launched that took a screenshot and launched the mdbg command line mdbg with a script that attached to the process, took off the list of loaded modules, the list of threads and their stacks, and disconnected:

     !a {0} !l -v modules !w -v all !block !fo p !de !quit

    The results could then be packaged and sent "home" by the main program.

Scroll to Top