While循环冻结C#程序
While Loop Freezing C# Program
我为我的期末项目之一制作的 Blackjack 程序遇到了层出不穷的问题。虽然我经常使用 while 循环,但在这种情况下,每当我实例化一个循环时,它都会冻结 windows 表单应用程序并且不允许任何输入。
我试过基于 int 值做 while 循环,把它放在 main 方法中,并尝试重写它好几次都没有成功。这是一个例子,我希望玩家的回合一直持续到他们点击“停止”。
public bool yourTurn;
public int num = 0;
public static Random rnd = new Random();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
yourTurn = true;
Play();
}
private void button3_Click(object sender, EventArgs e)
{
yourTurn = false;
}
private void Play()
{
button1.Visible = false;
while (yourTurn)
{
num++;
label1.Text = num.ToString();
}
}
private void EndGame()
{
yourTurn = false;
MessageBox.Show("Game Ended");
}
关于 windows 表单程序,您需要了解的是只有一个线程可以完成所有工作。当该线程未 运行 运行您的代码时,它会在其他地方执行重要的事情,例如绘制用户界面
您的用户将鼠标移到您的程序上,他们点击内容并按下键盘上的键。这些事情导致大量的小消息被发布到一个专用于您的程序的队列中。 Windows 发布消息并关注队列。当 运行 运行您的程序的线程未主动 运行 连接您的代码时,它正在使用这些消息。大多数情况下,它们可能会被丢弃,有时它们会导致操作,例如,如果您有一个按钮单击处理程序并且 Windows 发布一条用户已单击按钮 X 的消息,然后消费线程进入 您的代码 并开始执行您已编码到点击处理程序中的那些事情
让你离开这个线程是绝对重要的;您的点击处理程序快速完成其工作,然后您释放 thread/free 它返回到它通常所在的位置,做它通常做的事情(处理消息)。如果你长时间或永远持有它,windows 会注意到消息队列正在增长和增长,不再被消耗,因为你已经捕获了线程 - window 获得了一个“Not响应”消息并淡出 - Windows 在消息队列未被消耗的时间超过特定超时时执行此操作
做这样的事情将永远陷入 UI 线程:
bool keepLooping = true;
void ButtonX_Click(object sender, EventArgs e){
while(keepLooping)
Thread.Sleep(100);
}
Buttony_Click(object sender, EventArgs e){
keepLooping = false;
}
如果你先点击buttonX,游戏结束; UI 线程将进入点击处理程序并且永远无法逃脱。您有另一个会中断循环的点击处理程序并不重要。如果线程被困在处理程序 X 中并且您的用户单击按钮 Y,他们单击按钮的消息将被发布到队列中,但是 UI 线程已经被困在处理程序 X 中并且永远不会被允许去返回使用队列来发现该消息; Y 的处理程序永远不会是 运行 因为 UI 线程被困在 X 中,所以变量永远不会变为假,释放线程
时刻注意这一点;您的事件处理程序必须能够快速完成以保持良好的体验,或者它们必须包含特定的点,您可以在这些点释放线程以返回正常执行的操作,例如 await
指令同步操作。即使您的代码是一些简单的“下载一个 20 GB 的文件”指令,如果您通过某种方式在整个下载过程中占用 UI 线程的注意力,您也会得到一个“没有响应”——这个“不要长时间占据UI线程的注意力”对于拥有一个没有freeze/hang
的程序来说是至关重要的
我为我的期末项目之一制作的 Blackjack 程序遇到了层出不穷的问题。虽然我经常使用 while 循环,但在这种情况下,每当我实例化一个循环时,它都会冻结 windows 表单应用程序并且不允许任何输入。
我试过基于 int 值做 while 循环,把它放在 main 方法中,并尝试重写它好几次都没有成功。这是一个例子,我希望玩家的回合一直持续到他们点击“停止”。
public bool yourTurn;
public int num = 0;
public static Random rnd = new Random();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
yourTurn = true;
Play();
}
private void button3_Click(object sender, EventArgs e)
{
yourTurn = false;
}
private void Play()
{
button1.Visible = false;
while (yourTurn)
{
num++;
label1.Text = num.ToString();
}
}
private void EndGame()
{
yourTurn = false;
MessageBox.Show("Game Ended");
}
关于 windows 表单程序,您需要了解的是只有一个线程可以完成所有工作。当该线程未 运行 运行您的代码时,它会在其他地方执行重要的事情,例如绘制用户界面
您的用户将鼠标移到您的程序上,他们点击内容并按下键盘上的键。这些事情导致大量的小消息被发布到一个专用于您的程序的队列中。 Windows 发布消息并关注队列。当 运行 运行您的程序的线程未主动 运行 连接您的代码时,它正在使用这些消息。大多数情况下,它们可能会被丢弃,有时它们会导致操作,例如,如果您有一个按钮单击处理程序并且 Windows 发布一条用户已单击按钮 X 的消息,然后消费线程进入 您的代码 并开始执行您已编码到点击处理程序中的那些事情
让你离开这个线程是绝对重要的;您的点击处理程序快速完成其工作,然后您释放 thread/free 它返回到它通常所在的位置,做它通常做的事情(处理消息)。如果你长时间或永远持有它,windows 会注意到消息队列正在增长和增长,不再被消耗,因为你已经捕获了线程 - window 获得了一个“Not响应”消息并淡出 - Windows 在消息队列未被消耗的时间超过特定超时时执行此操作
做这样的事情将永远陷入 UI 线程:
bool keepLooping = true;
void ButtonX_Click(object sender, EventArgs e){
while(keepLooping)
Thread.Sleep(100);
}
Buttony_Click(object sender, EventArgs e){
keepLooping = false;
}
如果你先点击buttonX,游戏结束; UI 线程将进入点击处理程序并且永远无法逃脱。您有另一个会中断循环的点击处理程序并不重要。如果线程被困在处理程序 X 中并且您的用户单击按钮 Y,他们单击按钮的消息将被发布到队列中,但是 UI 线程已经被困在处理程序 X 中并且永远不会被允许去返回使用队列来发现该消息; Y 的处理程序永远不会是 运行 因为 UI 线程被困在 X 中,所以变量永远不会变为假,释放线程
时刻注意这一点;您的事件处理程序必须能够快速完成以保持良好的体验,或者它们必须包含特定的点,您可以在这些点释放线程以返回正常执行的操作,例如 await
指令同步操作。即使您的代码是一些简单的“下载一个 20 GB 的文件”指令,如果您通过某种方式在整个下载过程中占用 UI 线程的注意力,您也会得到一个“没有响应”——这个“不要长时间占据UI线程的注意力”对于拥有一个没有freeze/hang