gpt4 book ai didi

c# - 为什么在这个特定的 WinForms 应用程序中会发生死锁?

转载 作者:太空宇宙 更新时间:2023-11-03 21:40:21 25 4
gpt4 key购买 nike

我创建了一个带有文本框、设置按钮和切换按钮的简单 Windows 窗体。当我单击“切换”按钮时,会创建一个线程,将文本重复设置到文本框。当我再次单击按钮时,线程停止。当我单击“设置”按钮时,文本一次设置到文本框。如果我执行以下操作,则会发生死锁:

  1. 运行应用(在 Debug模式下)。
  2. 单击切换按钮让文本在文本框中运行。
  3. 点击设置按钮。 -> 这一步出现死锁。

您能解释一下为什么以及如何在这种情况下发生死锁吗?如何避免?

代码如下:

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

最佳答案

Can you explain why and how deadlock occurs in this situation?

当然...死锁的发生是因为 lock()/Invoke() 组合。

副线程在运行和更新的同时,获得了对象的锁。然后辅助线程调用 Invoke(),这是一个同步调用。关键是要认识到辅助线程实际上是在等待主 UI 线程在继续之前更新 TextBox。

当您单击“设置”按钮时,它会尝试更新但必须等待辅助线程释放锁。此时,主 UI 实际上停止并卡住在 lock() 行,等待辅助线程释放锁。在等待锁释放期间,主 UI 线程无法处理任何消息。

但是辅助线程在做什么呢?它当前拥有锁并正在等待主 UI 线程为其同步 Invoke() 调用提供服务。但是,由于主 UI 线程正在等待释放锁,因此它无法处理任何请求(包括 Invoke() 请求)并且 bam...DEADLOCK!他们都在等待对方。

How to avoid it?

切勿在主 UI 线程中使用 lock()。在某些情况下,从 Invoke() 切换到 BeginInvoke() 可以解决问题,因为 BeginInvoke() 是异步的。

关于c# - 为什么在这个特定的 WinForms 应用程序中会发生死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19614064/

25 4 0
文章推荐: html - 如何将下拉列表和表格元素放在页面的中心?
文章推荐: python - 无法让 Django Rest Framework ViewSet 识别用户的权限
文章推荐: html - 将
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com