为什么Windows窗体应用程序(C#)死锁?如何避免其锁定
本文关键字:何避免 锁定 死锁 窗体 Windows 应用程序 为什么 | 更新日期: 2023-09-27 18:01:03
根据文章Lock-Up Unlocked实现对死锁的C#Windows窗体应用程序的更改后,我仍然遇到与文章Lock-Up的前一段代码相同的问题!
也就是说,快速单击按钮几次后,应用程序就会挂断(变得没有响应(。
为什么
如何纠正?
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线程,导致出现"未响应"消息,因为表单没有可用的时间自行绘制。
实际上,您不需要锁定即可更新文本值。当您从Control
调用时,它只需将消息推送到UI消息队列中,该队列在UI线程上同步处理。你能做的最糟糕的事情就是种族条件,它不会破坏任何共享状态。
删除锁定,代码应该仍能正常工作。
我很犹豫是否提供任何示例代码,因为我不知道你想用这个示例实现什么。
在Windows中处理需要GUi访问的冲突线程的模式。Forms涉及InvokeRequired属性和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");
}
}
}