-1

Think We have this part in our program:

private void button1_Click(object sender, EventArgs e)
        {
            while (true) ;
        }

If we run the program it will crash and say "Not Responding". How to prevent this. I want the program check itself and if it dose not respond, restart itself.


Note:
We can use BackgroundWorker class. like this:

private readonly BackgroundWorker worker;

    public Form1()
            {
                InitializeComponent();

                worker = new BackgroundWorker();
                worker.WorkerReportsProgress = true;
                worker.DoWork += Form1_Load;
                worker.ProgressChanged += button1_Click;
                worker.RunWorkerCompleted += worker_RunWorkerCompleted;
            }

But there is no method or property or event in that class to understand not responding. Any help will be appreciate.


Edit 3:
I used BackgroundWorker with ThredTimer and checked if process is "Not Responding". This dose not close the program but start a new one.
Certainly this is not a clean code, but it is a way. I'm still looking for how to use BeginInvoke as @micky said Or other way to make this beautiful. Thanks to all of you
    private readonly BackgroundWorker _Worker;

    public Form1()
    {
        InitializeComponent();

        _Worker = new BackgroundWorker();
        _Worker.DoWork += new DoWorkEventHandler(_Worker_DoWork);
        _Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_Worker_RunWorkerCompleted);
        _Worker.WorkerReportsProgress = true;
        _Worker.WorkerSupportsCancellation = true;
    }


    // BCW starts here.
    private void button1_Click(object sender, EventArgs e)
    {
        _Worker.RunWorkerAsync();
        while (true) ;
    }

    // ThreadTimer will run here. 
    void _Worker_DoWork(object sender, DoWorkEventArgs e)
    {

        if (_Worker.IsBusy == true)
        {
            if (_Worker.CancellationPending)
            {
                e.Cancel = true;
            }
            TimerCallback tmrCallBack = new TimerCallback(CheckStatusThreadHealth);
            System.Threading.Timer tmr = new System.Threading.Timer(tmrCallBack, null, 10000, 10000);
        }

    }        


    // This will call by ThreadTimer and check processes for not responding
    public void CheckStatusThreadHealth(object IsBusy)
    {
        Process application = null;

        foreach (var process in Process.GetProcesses())
        {
            if (process.ProcessName == "WindowsFormsApplication1")
            {
                application = process;
                break;
            }
        }

        if (!application.Responding)
        {
            // This should end BCW and go to _Worker_RunWorkerCompleted. But it didn't
            _Worker.CancelAsync();

            // This Restart program but did not close the last one.
            Application.Restart();
        }
    }

    // this should run when BCW has error or cancel, But never this happen
    void _Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {

        Application.Restart();
        return;
    }
}



The Answer: Thanks to Jason Williams
I used a watch dog program as a solution and Communicate between two program by this link The code Changed to this:

In Main Program
public partial class Form1 : Form
{
    // Use SendMessage API
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr SendMessage(IntPtr hwnd, uint Msg, IntPtr wParam, IntPtr lParam);

    // define a message
    private const int RF_TESTMESSAGE = 0xA123;

    // The timer will begin with the form
    public Form1()
    {
        InitializeComponent();

        var timer = new Timer();
        timer.Tick += new EventHandler(timer_Tick);
        timer.Interval = 10000; //10 seconds
        timer.Start();
    }

    //Timer look for a Watch Dog Program and send message to it
    void timer_Tick(object sender, EventArgs e)
    {
        try
        {
            Process WatchDogProccess = Process.GetProcessesByName("Watch Dog")[0];
            SendMessage(WatchDogProccess.MainWindowHandle, RF_TESTMESSAGE, IntPtr.Zero, IntPtr.Zero);
        }
        catch
        {
         //if Watch Dog is not running, will reach here
        }
    }

    // if we click this button we will got "Not Responding"
    private void button1_Click(object sender, EventArgs e)
    {
        while (true) ;
    }
}



In Watch Dog Program

public partial class Form2 : Form
{
    //the message that have been define in main program
    private const int RF_TESTMESSAGE = 0xA123;

    //Recive the message
    protected override void WndProc(ref Message message)
    {
        if (message.Msg == RF_TESTMESSAGE)
        {
            // this mean the mian program run perfectly
        }
        else
        {
            //the main program is not responding

            //Main program's name and address
            string FileAddress = @"C:\Users\...\MainProgram.exe";
            string FileName = "MainProgram";

            // This will restart the main program
            RestartProgram(FileAddress, FileName);
        }
        base.WndProc(ref message);
    }

    // This will restart the main program
    public void RestartProgram(string FileAddress, string FileName)
    {
        //Find the Process
        Process[] prs = Process.GetProcessesByName(FileName);

        foreach (Process pr in prs)
        {
            if (!pr.Responding)
            {
                try
                {
                    pr.Kill();

                    //then to restart-
                    var process = new Process
                    {
                        StartInfo = new ProcessStartInfo
                        {
                            FileName = FileAddress
                        }
                    };
                    process.Start();
                }
                catch { }
            }
        }
    }
    public Form2()
    {
        InitializeComponent();

    }
}

}

  • It is normal that you have this. it is an infinity loop! – H. Pauwelyn Oct 31 '15 at 12:43
  • Check out the _Windows message pump_. Windows detects when a GUI app is not responding by whether it is making frequent calls to [GetMessage()](https://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx) (ultimately). Your simulation in `button1_Click()` will essentially "hang" the message pump. Messages will pile up and up. –  Oct 31 '15 at 13:04
  • @Hein Infinity loop is an example to force the program crash, But in real program I have that often crashes, especially in big data computing. – Arman Rasouli Oct 31 '15 at 13:06
  • Perhaps. I would have thought it was more an example of being _unresponsive_ than a _crash_ –  Oct 31 '15 at 13:28
  • @Micky. Thank you. But where I can check that, while program is on that hang? Should I use BackgroundWorker? – Arman Rasouli Oct 31 '15 at 16:01
  • Your `BackgroundWorker` code is confusing. Using methods like `Form1_Load()` (apparent handler for the `Load` event) and `button1_Click` (apparent handler for a `Click` event) for events like `DoWork` and `ProgressChanged` doesn't make any sense. If you are asking whether you should use a `BackgroundWorker` task to actually _monitor_ for an unresponsive program, I would say no; use a dedicated thread, rather than tying up a thread from the thread pool for the purpose. Beyond that, the question is pretty broad...try to solve it yourself, and ask if you have a _specific_ question that comes up. – Peter Duniho Oct 31 '15 at 18:26

1 Answers1

0

You could solve this with a background thread that somehow detects that the ui thread is not responding. But how would this thread reset/restart your ui thread? This could be very difficult to do cleanly, as you would somehow have to reset all the state throughout your app to a known good condition.

So the conventional approach is instead to have a separate "watch dog" process. This can detect that your app is dead, kill its process and then run a new instance.

So how to detect that it is dead? There are many clever ways you can do this, but the simplest and most reliable is to just send a message from your app to the watch dog periodically (e.g. once per second) using a Windows forms timer - if your ui thread is busy it will not process the timer event and so the message won't be sent, and after a few seconds your watch dog will be confident that it is unresponsive, and be able to restart it.

Jason Williams
  • 56,972
  • 11
  • 108
  • 137