我创建了一个带有文本框、设置按钮和切换按钮的简单 Windows 窗体。当我单击“切换”按钮时,会创建一个线程,将文本重复设置到文本框。当我再次单击该按钮时,线程停止。当我单击“设置”按钮时,会在文本框中设置一次文本。如果我执行以下操作,则会发生死锁:
- 运行应用程序(在调试模式下)。
- 单击切换按钮让文本在文本框中运行。
- 单击设置按钮。-> 这一步发生死锁。
你能解释一下在这种情况下为什么会发生死锁以及如何发生死锁吗?如何避免?
下面是代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace DeadLockTest
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace DeadLockTest
{
public class Form1 : Form
{
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private int counter;
private Thread thread;
private bool cancelRequested;
private string content;
private object lockKey = new object();
public Form1()
{
InitializeComponent();
}
protected void UpdateContent()
{
this.textBox1.Text = this.content;
}
protected void InvokeUpdateContent()
{
lock (this.lockKey)
{
if (InvokeRequired)
{
Invoke(new Action(UpdateContent));
}
else
{
UpdateContent();
}
}
}
protected void SetText(string text)
{
this.content = text;
InvokeUpdateContent();
}
protected void StressTest()
{
int localCounter = 0;
while (!this.cancelRequested)
{
SetText(string.Format("{0}", localCounter++));
}
this.cancelRequested = false;
this.thread = null;
}
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.textBox1.Location = new System.Drawing.Point(12, 12);
this.textBox1.Name = "textBox1";
this.textBox1.ReadOnly = true;
this.textBox1.Size = new System.Drawing.Size(260, 20);
this.textBox1.TabIndex = 0;
//
// button1
//
this.button1.Location = new System.Drawing.Point(12, 38);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 1;
this.button1.Text = "Set";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(93, 38);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 2;
this.button2.Text = "Toggle";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 262);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.textBox1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
private void button1_Click(object sender, EventArgs e)
{
SetText(string.Format("{0}", this.counter++));
}
private void button2_Click(object sender, EventArgs e)
{
if (this.thread == null)
{
this.thread = new Thread(new ThreadStart(StressTest));
thread.Start();
}
else
{
this.cancelRequested = true;
}
}
}
}