简体   繁体   中英

Why is Windows Form app (C#) deadlocked and how to avoid its lockup?

After implementing the changes to deadlocked C# Windows Form Application according to the article Lock Up Unlocked I am still having the same problem as in previous code of article Locked Up!

That is, upon clicking the button few times rapidly, the application hangs up (becomes unresponsive).

Why?
And how to correct it?

using System;
using System.Windows.Forms;
using System.Threading;

namespace LockupUnlocked
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
      _t = new Thread(new ParameterizedThreadStart(WorkerThread));
    }

    private Thread _t;
    private object lockObject = new object();

    private bool StopThread = false;  ////changes added to avoid deadlock

    private void WorkerThread(object sender)
    {
      Thread.Sleep(1000);
      //while (true)
      while (!StopThread)//changes added to avoid deadlock
      {
        string result = "This is a Test";
        IAsyncResult aResult;////changes added to avoid deadlock
        lock (lockObject)
        {
          Thread.Sleep(25);
          //lblResult.Invoke(new MethodInvoker(delegate { lblResult.Text = result; }));
          aResult = lblResult.BeginInvoke//changes to avoid deadlock
            (new MethodInvoker(delegate { lblResult.Text = result; }));
        }
        lblResult.EndInvoke(aResult);//changes added to avoid deadlock
        Thread.Sleep(500);
      }
    }
    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
      StopThread = true;
    }
    private void Form1_Load(object sender, EventArgs e)
    {
      _t.Start();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      lock (lockObject)//changes added to avoid deadlock
      {
        lblResult.Text = "Override the Test";
      }
    }
  }
}

To me it looks like lock contention, not necessarily dead-locking.

You iterate a while loop every 25 milliseconds (not 25 seconds, that'd be 25000), clicking the button would then interrupt this asking for a lock, it may never be given that lock as the sleep is inside the lock scope.

Without clicking the button this may appear to work, however, the button click waiting on a lock will be blocking the UI thread, causing the "not responding" message to appear because the form doesn't have available time to paint itself.

You actually don't need to lock in order to update the text value. When you invoke from a Control , it simply pushes a message onto the UI message queue, which is processed synchronously on the UI thread. The worst you can do is a race condition, which won't corrupt any shared state.

Remove the locking and the code should still work as you expect.


I am hesitant to offer up any sample code as I don't know what you are trying to achieve with this sample.

The pattern to work with conflicting threads that need GUi access in Windows.Forms involves the InvokeRequired property and the Invoke function. Locking is not neccessary then.

namespace WindowsFormsApplication1
{
  using System;
  using System.Threading;
  using System.Windows.Forms;

  public partial class Form1 : Form
  {
    private Thread thread;

    public Form1()
    {
      this.InitializeComponent();
      this.thread = new Thread(this.WorkerThread);
    }

    private void WorkerThread(object sender)
    {
      Thread.Sleep(1000);

      while (true)
      {
        Thread.Sleep(25);

        this.SetText("from thread");

        Thread.Sleep(500);
      }
    }

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
      this.thread.Abort();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      this.thread.Start();
    }

    /// <summary>
    /// This is a callback for the SetText Method.
    /// </summary>
    /// <param name="text">The text.</param>
    private delegate void SetTextCallback(string text);

    /// <summary>
    /// This sets a text. 
    /// It's thread safe, you can call this function from any thread. 
    /// If it's not called from the UI-thread, it will invoke itself
    /// on the UI thread.
    /// </summary>
    /// <param name="text">The text.</param>
    private void SetText(string text)
    {
      if (this.InvokeRequired)
      {
        this.Invoke(new SetTextCallback(this.SetText), text);
      }
      else
      {
        this.lblResult.Text = text;  
      }
    }

    private void Button1_Click(object sender, EventArgs e)
    {
      this.SetText("from button");
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM