locked
Form (GUI) hangs when starting threads RRS feed

  • Question

  • Hello,
    I'm experimenting with threading in C# and I have this code

            private void button1_Click(object sender, EventArgs e) 
            { 
                for (int i = 0; i < numericUpDown1.Value; i++) 
                { 
                    list.Add(new Thread(new ThreadStart(Callback))); 
                    list[i].Start(); 
                } 
            } 

    where Callback() is a long, intensive operation.

    When I Click on the Button, the form (GUI) hangs. Why does it hang if the "long, intensive operation" run on separate threads (not the form thread)?

    Thank you very much.
    Wednesday, December 10, 2008 2:50 PM

Answers

  • ekerazha said:

    ... and do you have any idea why the "parent thread + join() trick" does avoid the hanging (while using the same "CPU intensive" code)?

    Yes - it's because you're starting the thread and then waiting for it to finish before going on to start the next thread. So you don't actually have more than one worker thread running at once.

    I think your main problem is that your threads are using 100% CPU. Is there a place in the thread code where you could put a Thread.Sleep(0) in a loop? That might make things work. (Or maybe a thread.Sleep(100) if that doesn't work.)
    • Marked as answer by ekerazha Thursday, December 11, 2008 10:23 AM
    Thursday, December 11, 2008 9:44 AM

All replies

  • What is the value of numericUpDown1.Value?

    Does Callback() try to interact with the user interface?
    Wednesday, December 10, 2008 3:16 PM
  • It could be 8 (I'm testing using 8).

    I've seen the GUI doesn't hang when it is 1 or 2 (so 1 or 2 threads) while it does hang with values > 2 I can't understand why.
    Wednesday, December 10, 2008 3:21 PM
  • Your UI possibly hangs because of the High CPU utilization of your system due to other threads.

    Two things can be helpful.

    1. Put Application.DoEvents in the main thread wherever you feel like.

    2. Lower priority of the threads that you are forking.

    Let me know if that helps.

    Thanks,
    Viral.
    Wednesday, December 10, 2008 3:36 PM
  • Thank you for your reply.

    1. I don't exactly know where I can put Application.DoEvents() as the GUI thread just starts that threads. However it seems like this doesn't help.

    2. I need threads with normal or high priority. The point is that other applications on the system don't hang, just the one which starts my threads.

    However I've found this way the form doesn't hang (I don't know why eh eh and it seems a bit hackish):
            private void button1_Click(object sender, EventArgs e) 
            { 
                Thread t = new Thread(new ThreadStart(Execute)); 
                t.Start(); 
            } 
     
            private void Execute() 
            { 
                for (int i = 0; i < numericUpDown1.Value; i++) 
                { 
                    list.Add(new Thread(new ThreadStart(Callback))); 
                    list[i].Start(); 
                    list[i].Join(); 
                }        
            } 


    The trick is

    a. Don't start the threads directly, but start a "parent" thread which then starts the other threads.
    b. Add list[i].Join()

    BUT this causes other problems.

    Any idea?
    Wednesday, December 10, 2008 3:53 PM
  • You can set your thread.IsBackground property to true, but then if your callback does anything to the UI you will need to call Invoke() to invoke a delegate on the UI thread in order to update the UI.  The UI cannot/should not be updated from a background thread.  Using Application.DoEvents() is risky and can lead to unexpected and hard to debug behavior.





    If this answers your question, please mark the question as answered.
    Wednesday, December 10, 2008 4:30 PM
  • My threads don't update the UI, but I've already tried IsBackground = true and it doesn't work, nothing change.
    Wednesday, December 10, 2008 4:35 PM
  • Viral Jain said:

    1. Put Application.DoEvents in the main thread wherever you feel like.

    There's two problems with that:

    (1) Calling Application.DoEvents() from a thread is tantamount to saying "please give me some weird and difficult to find bugs" and
    (2) Calling it from the main UI thread doesn't really help unless the main UI thread is itself in some kind of long lived loop. (By long lived, I mean longer than a second or so). It does have other weird side effect though.

    See some of the comments at the end of the MS article on DoEvents():

    http://msdn.microsoft.com/en-us/library/system.windows.forms.application.doevents.aspx

    Unexpected reentrancy in UI code can be VERY nasty.
    Wednesday, December 10, 2008 4:53 PM
  • ekerazha said:

    My threads don't update the UI, but I've already tried IsBackground = true and it doesn't work, nothing change.


    Ok, replace your thread code with this:

    void Callback()
    {
          for (int i = 0; i < 100; ++i)
          {
                 Thread.Sleep(1000);
          }
    }

    Does it still hang?

    Then change it to:

    void Callback()
    {
         int endTime = System.Environment.TickCount + 100000;

        while (System.Environment.TickCount  < endTime)
        {
              Sleep(0);
        }
    }

    Does it hang now?

    Finally:

    void Callback()
    {
         int endTime = System.Environment.TickCount + 100000;

        while (System.Environment.TickCount  < endTime)
        {
            // Very busy loop
        }
    }

    Now does it hang?

    By the way, doing this:

    list[i].Start();
    list[i].Join();

    simply starts the thread and then waits for it to terminate. It's pretty much the same as just calling Callback() without starting a separate thread for it!

    Wednesday, December 10, 2008 5:00 PM
  • BigTuna99 said:

    You can set your thread.IsBackground property to true, but then if your callback does anything to the UI you will need to call Invoke() to invoke a delegate on the UI thread in order to update the UI. 

    I think you must have misunderstood what Thread.IsBackground does. The only effect it has is at program (i.e process) termination. If any thread is running that is NOT marked as IsBackground, then the process will not terminate until each non-background thread has terminated. However, if all threads are background, then they will be automatically killed when the process wants to terminate.
    Wednesday, December 10, 2008 5:05 PM
  • Matthew Watson said:

    [...]

    1st code: doesn't hang, CPU is not 100%
    2nd code: doesn't hang, CPU is 100%
    3rd code: hangs, CPU is 100%

    So could it be related to my "CPU intensive" code? Strange...

    ... and do you have any idea why the "parent thread + join() trick" does avoid the hanging (while using the same "CPU intensive" code)?

    Thank you.
    Wednesday, December 10, 2008 5:26 PM
  • Using this code, GUI does hang

            void Callback() 
            { 
                int endTime = System.Environment.TickCount + 100000; 
     
                while (System.Environment.TickCount < endTime) 
                { 
                    // Very busy loop 
                    string original; 
                    for (int i = 0; i < 200000; i++) 
                    { 
                        original = i.ToString(); 
                    } 
                } 
            } 


    Wednesday, December 10, 2008 7:17 PM
  • ekerazha said:

    ... and do you have any idea why the "parent thread + join() trick" does avoid the hanging (while using the same "CPU intensive" code)?

    Yes - it's because you're starting the thread and then waiting for it to finish before going on to start the next thread. So you don't actually have more than one worker thread running at once.

    I think your main problem is that your threads are using 100% CPU. Is there a place in the thread code where you could put a Thread.Sleep(0) in a loop? That might make things work. (Or maybe a thread.Sleep(100) if that doesn't work.)
    • Marked as answer by ekerazha Thursday, December 11, 2008 10:23 AM
    Thursday, December 11, 2008 9:44 AM
  • Thread.Sleep(0); makes the trick. I think this can be acceptable. Thank you very much.

    The strange thing is that the parent thread hangs, while the other applications don't. Maybe there's room for improving the Microsoft Windows (Vista) Scheduler.
    Thursday, December 11, 2008 10:22 AM