简体   繁体   English

为什么Windows窗体应用程序(C#)陷入僵局以及如何避免其锁定?

[英]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! 根据文章锁定解锁实现对死锁C#Windows窗体应用程序的更改后,我仍然遇到与之前的文章锁定相同的问题

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. 你每隔25毫秒(不是25秒,那就是25000)迭代一个while循环,然后单击按钮会中断这个请求锁定,因为睡眠在锁定范围内,所以可能永远不会给出该锁定。

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. 没有单击按钮这似乎可以工作,但是,等待锁定的按钮单击将阻止UI线程,导致“无响应”消息出现,因为表单没有可用的时间来绘制自己。

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. 当您从Control调用时,它只是将消息推送到UI消息队列,该消息队列在UI线程上同步处理。 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. 使用Windows.Forms中需要GUi访问的冲突线程的模式涉及InvokeRequired属性和Invoke函数。 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");
    }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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