0

According to answer for this question Why Thread.Join() DOES NOT hang my application when called on UI thread? thread.Join should not hang UI if it called from STA thread. I used the same code as in linked question

    private void button1_Click(object sender, EventArgs e)
    {
        string retValue = "";
        Thread thread = new Thread(
        () =>
        {
            retValue = LongRunningHeavyFunction();
        });
        thread.Start();
        thread.Join();
        button1.Text = retValue;
    }

    private string LongRunningHeavyFunction()
    {
        Thread.Sleep(5000);
        return "Done";
    }

Method Main in class Program marked as [STAThread]. But when I press button UI is freezed, I can't drag window etc. I'm confused. Am I missed something? Why UI is freezed in my case?

Community
  • 1
  • 1
Seleznev Stas
  • 27
  • 1
  • 3
  • It hangs because you're blocking the UI thread for 5 seconds. –  Apr 13 '17 at 21:28
  • You said "worker A should hire worker B and ask him to sleep for five years; worker A should do nothing until worker B is awake again"; it should not be surprising that worker A -- the UI thread -- does **nothing**. Updating the UI is not **nothing**. Now, it turns out that worker A does in fact do a little work, but not very much. Not enough that you should rely on it. – Eric Lippert Apr 13 '17 at 21:30
  • 1
    What you are doing is a gross violation of the [STAThread] contract. The CLR does *some* pumping to avoid deadlock but only a subset of notifications are dispatched. Not user input, so dragging the window cannot work. Or clicking the button for that matter, note the very nasty re-entrancy problem that would cause, DoEvents() style. **Never** do this. You never have to. – Hans Passant Apr 13 '17 at 21:31
  • Thanks, I just misunderstood linked question. I thought that UI is fully responsive and I wondered how it can be and why it's false in my case – Seleznev Stas Apr 13 '17 at 21:55
  • 1
    Dunno why this question's received so many downvotes. All the asker needed to know was to call back the dispatcher rather than use a thread join. Easy fix. – Nat Apr 13 '17 at 22:06
  • Ah I may've missed the point of this question. I saw broken code and figured it needing fixing; but it looks like this question was actually about _why_ it behaves differently from what another question/answer alleged? I don't know about issues `thread.Join()` might have with STA threads; calling the GUI dispatcher's the way to get around those problems, but I dunno the low-level details about why those problems exist in the first place. – Nat Apr 13 '17 at 22:29
  • It probably better to mark event handler as `async` and wrap your code with `Task` rather than `Thread` – VMAtm Apr 14 '17 at 01:58

2 Answers2

0

Thread.Sleep causes UI to freeze.

If you want to wait for a while in LongRunningHeavyFunction(), use a timer object.

Here is an example, how to use timer:

How to use a timer to wait?

Community
  • 1
  • 1
Pavan Chandaka
  • 11,671
  • 5
  • 26
  • 34
0

thread.Join() tells the current thread to await thread. In this case, the current thread is the GUI thread, and you're telling it to await the worker thread. As a result, your GUI thread does nothing until the worker thread completes. And since the GUI thread is doing nothing, it isn't handling normal GUI activities, causing the freeze.

The solution is to not block your GUI. Instead, run your long-running process without awaiting it, such that your GUI thread can keep responding to the user. Then, once the long-running process does complete, use the GUI dispatcher to call back to set the result.

The code might look something like this:

private void button1_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(
    () =>
    {
        //  Perform work
        var retValue = LongRunningHeavyFunction();

        //  Call the GUI thread
        button1.Dispatcher.BeginInvoke(() =>
        {
            //  .Dispatcher called the GUI thread.
            //  This code happens back in the GUI thread once the
            //  worker thread has completed.

            button1.Text = retValue;
        });
    });
    thread.Start();
}

private string LongRunningHeavyFunction()
{
    Thread.Sleep(5000);
    return "Done";
}
Nat
  • 1,085
  • 2
  • 18
  • 35