gpt4 book ai didi

c# - 为什么在任务中运行的 Thread.Sleep 不会阻塞 WinForms UI 线程?

转载 作者:太空狗 更新时间:2023-10-30 00:40:40 27 4
gpt4 key购买 nike

我目前正在使用 C# 和窗口窗体中的任务,我遇到了一个奇怪的效果。我有一个表单,其中包含一个每 300 毫秒计时一次的计时器。 tick 事件将该窗体中控件的背景更改为随机颜色。我有另一个按钮,单击它会启动一个新任务,该任务仅使用 Thread.Sleep 等待 3 秒。我还插入了一个用于记录的文本框。

根据我对任务的了解,他们不会创建新线程来运行任务(并且日志也显示了这一点),我希望第一个按钮在任务运行时停止更改颜色 3 秒,因为一个线程一次只能做一件事。该按钮要么闪烁,要么在 3 秒内什么都不做。

然而,这个假设似乎是错误的,因为按钮会很高兴地改变它的颜色,即使在线程理应休眠时也是如此!怎么会这样?

跟进:我注意到,从任务方法中,我必须使用 Invoke 来访问日志文本框。但是,根据 MSDN 的 Control.InvokeRequired文档:

true if the control's Handle was created on a different thread than the calling thread (indicating that you must make calls to the control through an invoke method); otherwise, false.

既然这是一个单线程场景,InvokeRequired 怎么可能是真的?

附注:我知道 Task.Delay 是一回事。我想了解为什么 UI 线程在 Thread.Sleep 期间不阻塞。

日志输出::

[T9] Before await
[T9] [I] Task Start
[T9] [I] Task End
[T9] After await

闪烁的按钮还显示了执行 tick 事件处理程序的线程的线程 ID,也是 9。

完整代码:

using System;
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AsyncAwaitTest
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}

public class Form1 : Form
{
private readonly Button _buttonFlash;
private readonly System.Windows.Forms.Timer _timerFlash;
private readonly TextBox _textLog;

private readonly Random _rand = new Random();

public Form1()
{
_buttonFlash = new Button();
var buttonAwait = new Button();
_timerFlash = new System.Windows.Forms.Timer();
_textLog = new TextBox();
SuspendLayout();

_buttonFlash.Location = new Point(12, 12);
_buttonFlash.Size = new Size(139, 61);

buttonAwait.Location = new Point(213, 12);
buttonAwait.Size = new Size(110, 61);
buttonAwait.Text = "Wait Some Time";
buttonAwait.Click += buttonAwait_Click;

_timerFlash.Interval = 300;
_timerFlash.Tick += TimerFlashTick;

_textLog.Location = new Point(36, 79);
_textLog.Multiline = true;
_textLog.Size = new Size(351, 167);

ClientSize = new Size(480, 286);
Controls.Add(_textLog);
Controls.Add(buttonAwait);
Controls.Add(_buttonFlash);
Text = "Form1";

ResumeLayout(false);
PerformLayout();
}

protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
_timerFlash.Start();
}

private void Log(string text)
{
if (InvokeRequired)
{
Invoke((Action<string>) Log, "[I] " + text);
return;
}
_textLog.Text += string.Format("[T{0}] {1}{2}", Thread.CurrentThread.ManagedThreadId, text, Environment.NewLine);
}

private void TimerFlashTick(object sender, EventArgs e)
{
_buttonFlash.Text = Thread.CurrentThread.ManagedThreadId.ToString();
_buttonFlash.BackColor = Color.FromArgb(255, _rand.Next(0, 255), _rand.Next(0, 255), _rand.Next(0, 255));
}

private async void buttonAwait_Click(object sender, EventArgs e)
{
Log("Before await");
await Task.Factory.StartNew(Something);
Log("After await");
}

private void Something()
{
Log("Task Start");
Thread.Sleep(3000);
Log("Task End");
}
}
}

最佳答案

Since from what I understand about Tasks they don't create new threads to run the tasks on

Task 不一定创建新线程自身,但 Task.Factory.StartNew 会。它使用当前任务调度程序安排要执行的任务,默认情况下,它从线程池中获取一个工作线程。

请阅读:

http://msdn.microsoft.com/en-us/library/dd997402(v=vs.110).aspx

关于c# - 为什么在任务中运行的 Thread.Sleep 不会阻塞 WinForms UI 线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25513661/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com