C# 这个阻塞线程调用是如何实现的;“释放”;它本身
我正在运行一个基本的单线程应用程序 通常,在调用C# 这个阻塞线程调用是如何实现的;“释放”;它本身,c#,multithreading,winforms,timer,C#,Multithreading,Winforms,Timer,我正在运行一个基本的单线程应用程序 通常,在调用System.Windows.Forms.MessageBox.Show()时,人们希望此调用能够有效地阻止进一步的执行,直到此方法返回为止 但是,当使用System.Windows.Forms.Timer时,*相同的*线程似乎在某种程度上释放了自己,计时器的勾号事件在同一线程上触发 到底发生了什么事?我觉得这可能与穿线公寓有关,但我想澄清一下 以最简单的形式重新创建为控制台应用程序,如下所示: class Program { static
System.Windows.Forms.MessageBox.Show()
时,人们希望此调用能够有效地阻止进一步的执行,直到此方法返回为止
但是,当使用System.Windows.Forms.Timer
时,*相同的*线程似乎在某种程度上释放了自己,计时器的勾号事件在同一线程上触发
到底发生了什么事?我觉得这可能与穿线公寓有关,但我想澄清一下
以最简单的形式重新创建为控制台应用程序,如下所示:
class Program
{
static void Main(string[] args)
{
new Program();
while (true)
{
System.Windows.Forms.Application.DoEvents();
}
}
private System.Windows.Forms.Timer timer;
public Program()
{
timer = new System.Windows.Forms.Timer() { Interval = 2000 };
timer.Tick += timer_Tick;
timer.Start();
}
private void timer_Tick(object sender, EventArgs e)
{
Console.WriteLine(string.Format("Thread {0} has entered", Thread.CurrentThread.ManagedThreadId));
var result = MessageBox.Show("Test");
Console.WriteLine(string.Format("Thread {0} has left", Thread.CurrentThread.ManagedThreadId));
}
}
输出:
线程10已进入
线程10已进入
线程10已进入
线程10已进入
线程10已进入
当显示消息框等模式窗口时,Windows消息泵将继续运行
如果没有,当您在模态窗口前面移动模态窗口时,模态窗口后面的窗口显示将不会更新
由于Windows消息仍在泵送,“WM_定时器”消息仍将发送到非前台窗口,因此您将看到您注意到的行为
需要注意的关键是,Windows计时器会导致Windows将“WM_timer”消息发布到窗口的事件队列中,只要窗口的消息泵正在运行,计时器事件就会继续处理
避免再次进入的一个常见方法是在处理滴答声时禁用计时器
例如,将记号处理代码放入名为handleTimer()
的方法中,然后按如下方式处理记号:
private void timer_Tick(object sender, EventArgs e)
{
timer.Enabled = false;
try
{
handleTimer();
}
finally
{
timer.Enabled = true;
}
}
(发生异常时,您可能不希望重新启用计时器,在这种情况下,您不需要上面的try/finally
逻辑。)当显示消息框等模式窗口时,Windows消息泵将继续运行
如果没有,当您在模态窗口前面移动模态窗口时,模态窗口后面的窗口显示将不会更新
由于Windows消息仍在泵送,“WM_定时器”消息仍将发送到非前台窗口,因此您将看到您注意到的行为
需要注意的关键是,Windows计时器会导致Windows将“WM_timer”消息发布到窗口的事件队列中,只要窗口的消息泵正在运行,计时器事件就会继续处理
避免再次进入的一个常见方法是在处理滴答声时禁用计时器
例如,将记号处理代码放入名为handleTimer()
的方法中,然后按如下方式处理记号:
private void timer_Tick(object sender, EventArgs e)
{
timer.Enabled = false;
try
{
handleTimer();
}
finally
{
timer.Enabled = true;
}
}
(在发生异常时,您可能不想重新启用计时器,在这种情况下,您不需要上面的try/finally
逻辑。)这不是一个好的测试程序,因为调用Application.DoEvents()
将准确给出这种行为。你能用一个简单的Windows Forms应用程序复制它吗?我只是在我的简短示例中调用它,因为这是默认的winforms应用程序所能做的。默认的winforms应用程序不会调用Application.DoEvents()
创建一个winforms应用程序,在其上粘贴一个winforms计时器,你会观察到完全相同的行为。事实上,但我刚才指出,控制台应用程序调用Application.DoEvents()并不是一个等价的测试。这不是一个好的测试程序,因为调用Application.DoEvents()
将给出这种行为。你能用一个简单的Windows Forms应用程序复制它吗?我只是在我的简短示例中调用它,因为这是默认的winforms应用程序所能做的。默认的winforms应用程序不会调用Application.DoEvents()
创建一个winforms应用程序,在其上粘贴一个winforms计时器,你会观察到完全相同的行为。事实上,但我刚刚指出,控制台应用程序调用Application.DoEvents()并不是一个等价的测试。没有“同一线程”锁这样的东西,那么除了手动使用bool
手动阻止之外,还有什么方法可以阻止这种重复吗?@maxp我通常做的是调用timer.Enabled=false
作为处理程序中的第一件事,然后timer.Enabled=true代码>作为最后一件事。我将把它添加到我的答案中。没有“同一线程”锁这样的东西,那么除了手动使用bool
来手动阻止之外,还有什么方法可以阻止这种重复吗?@maxp我通常做的是调用timer.Enabled=false
作为处理程序中的第一件事,然后timer.Enabled=true代码>作为最后一件事。我会在我的回答中加上这个。