views:

57

answers:

3

Hi, after reading a few articles, I am still not sure I understand Multi-threading to solve my particular problem.

I have a Main form which will start a background worker thread(worker). The worker thread will doing a While(!Stopping) infinity loop and will sleep at end of each iteration terminate by global Stopping object(Read only lock object). With working fine when user press Stop button, the worker will stop after current iteration.

Now I want when user close the main form, it will set Stop flag first, let the worker thread finish its current job. After that the main form will close. Seems simple enough, but I couldn't make it working.

I tried either worker.Join(), or test woker.IsAlive in a while loop, but both case will lock the application(Main form) after a few seconds for some reason ?

The following is my code inside Form_Closing event handler (not working):

               // Tell the thread to stop the file
                Stop();
                Logger.Info("Stopping the thread by Close the application");
               //Not working as well                    
               //worker.Join();
                while (worker.IsAlive)
                {
                    Thread.Sleep(5000);
                    Logger.Info("After sleep for 5 seconds");
                }
                Logger.Info("worker thread stopped");

One thing interesting is that the worker thread seems always writes log event until the end of each loop iteration, then the rest of the log entry will be main form event inside the while(worker.IsAlive) loop.

A: 

You are creating a deadlock somehow put a break point everywhere you request and release the locking object. Also you can use the system.threading.monitor class to test to see if the lock is available rather then creating a deadlock. Get Very familiar with the threads window in VS.

rerun
Unfortunately, this is our first project need .NET 4.0 and as a result I am currently working using VS2010 Express. Doesn't looks like it has thread window for debug.
pstar
A: 

Join will always wait on the thread, using it in the UI thread will make application seem to be locked. IsAlive do not block anything in the GUI thread, it's your Thread.Sleep.

do somethnig like this instead:

while (worker.IsAlive)
{
    Thread.sleep(50);
    Application.DoEvents();
}
jgauffin
Thank you, this solution seems working well.
pstar
then please accept the answer by clicking on the "V"
jgauffin
A: 

Keep in mind that any code you use that causes the UI thread to suspend its normal obligation of pumping messages will manifest itself as a hang to the user. In other words, do not call any method which may block including Thread.Join, Thread.Sleep, WaitHandle.WaitOne, etc.

Since you want the worker to terminate upon closing the form then I suggest letting the form close after the stop signal has been sent to the worker thread. Add a Thread.Join call to the entry point of your application after the call to Application.Run. Since you are shutting down the application it is safe to call Thread.Abort if the thread does not respond in a timely manner. Here is some example code.

public void Main(string[] args)
{
  var form = new YourForm();
  Application.Run(form);
  if (!form.WorkerThread.Join(TIME_TO_WAIT))
  {
    form.WorkerThread.Abort();
  }
}
Brian Gideon
Thank Brian Gideon, I did test your solution but my main form will close instantaneous. The problem is that I don't really understood your solution, not sure I implemented it the right way.
pstar
Basically I now just call Stop() to set the stop flag for the worker Thread in the closing event of the form. And I think at that point my main Form will be closed and the execution will come back the the program.cs to the line: if(!form.WorkerThread.Join(TIME_TO_WAIT)) but as the main Form is closed at that point, and seems Logger function doesn't working from that point as well, how do I know what happened from that point?
pstar