为什么Windows窗体应用程序(C#)处于死锁状态,以及如何避免其锁定?

为什么Windows窗体应用程序(C#)处于死锁状态,以及如何避免其锁定?,c#,multithreading,debugging,synchronization,deadlock,C#,Multithreading,Debugging,Synchronization,Deadlock,在根据本文实现了对死锁的C#Windows窗体应用程序的更改之后,我仍然遇到与本文前面代码相同的问题 也就是说,快速单击按钮几次后,应用程序将挂起(变得无响应) 为什么? 如何纠正呢 using System; using System.Windows.Forms; using System.Threading; namespace LockupUnlocked { public partial class Form1 : Form { public Form1() {

在根据本文实现了对死锁的C#Windows窗体应用程序的更改之后,我仍然遇到与本文前面代码相同的问题

也就是说,快速单击按钮几次后,应用程序将挂起(变得无响应)

为什么?
如何纠正呢

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";
      }
    }
  }
}

对我来说,它看起来像是锁争用,而不一定是死锁

您每25毫秒(不是25秒,也就是25000秒)迭代一次while循环,然后单击按钮将中断请求锁的过程,因为睡眠在锁的作用域内,所以可能永远不会得到锁

如果不单击按钮,这看起来可能会起作用,但是,按钮单击等待锁定将阻塞UI线程,导致出现“无响应”消息,因为表单没有时间绘制自身

实际上,更新文本值不需要锁定。当您从
控件调用时,它只是将消息推送到UI消息队列上,该队列在UI线程上同步处理。你能做的最糟糕的事情就是竞争条件,它不会破坏任何共享状态

移除锁定后,代码仍应按预期工作。

我不太愿意提供任何示例代码,因为我不知道您试图用此示例实现什么。

在Windows中处理需要GUi访问的冲突线程的模式。表单涉及invokererequired属性和Invoke函数。那就不需要锁了

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");
    }
  }
}
命名空间窗口窗体应用程序1
{
使用制度;
使用系统线程;
使用System.Windows.Forms;
公共部分类Form1:Form
{
私有线程;
公共表格1()
{
this.InitializeComponent();
this.thread=新线程(this.WorkerThread);
}
私有void WorkerThread(对象发送器)
{
睡眠(1000);
while(true)
{
睡眠(25);
this.SetText(“来自线程”);
睡眠(500);
}
}
私有作废Form1\u FormClosing(对象发送方,FormClosingEventArgs e)
{
this.thread.Abort();
}
私有void Form1\u加载(对象发送方、事件参数e)
{
this.thread.Start();
}
/// 
///这是SetText方法的回调。
/// 
///文本。
私有委托void SetTextCallback(字符串文本);
/// 
///这将设置一个文本。
///它是线程安全的,您可以从任何线程调用此函数。
///如果没有从UI线程调用它,它将调用自身
///在UI线程上。
/// 
///文本。
私有void SetText(字符串文本)
{
if(this.invokererequired)
{
调用(新的SetTextCallback(this.SetText),text);
}
其他的
{
this.lblResult.Text=文本;
}
}
私有无效按钮1\u单击(对象发送者,事件参数e)
{
此.SetText(“从按钮”);
}
}
}

应用程序最终会再次响应吗?如果你问我,这是个糟糕的例子。lblResult。文本读取/写入总是在GUI线程上执行,不需要任何锁来运行。同意,这似乎是原因。具有讽刺意味的是,一些标有“更改以避免死锁”等注释的代码看起来更可能导致死锁。尽管我的应用程序不包含
textBox1
(这里是标签
lblResult
),但感谢您的代码。我编辑了它,不得不重新创建表单,并保留了默认名称。