单击按钮时,我将从主窗口打开一个新的子窗口。加载后,子窗口将使用鼠标光标位置跟踪器启动任务。子窗口关闭时,信号变量
stopMouseTracker
设置为 true
并且任务中的无限循环应该终止。下面的代码在调试和发布中都适用,无需代码优化。但是,当我在启用代码优化的发布中运行代码时,子窗口在我尝试关闭它后冻结。什么可能导致问题?
主窗口:
public MainWindow()
{
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e)
{
SubWindow subWindow = new();
subWindow.ShowDialog();
}
子窗口:
bool mouseTrackerOn = false;
bool stopMouseTracker = false;
public SubWindow()
{
InitializeComponent();
StartMouseTracker();
}
private void StartMouseTracker()
{
mouseTrackerOn = true;
Task.Factory.StartNew(() =>
{
while (!stopMouseTracker)
{
var p = System.Windows.Forms.Cursor.Position;
// Write cursor coordinates to text box tbXY
tbXY.Dispatcher.BeginInvoke(() => tbXY.Text = $"{p.X} {p.Y}");
Thread.Sleep(1);
}
mouseTrackerOn = false;
});
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
stopMouseTracker = true;
// This blocks the thread completely in Release with code optimization on
while (mouseTrackerOn) ;
}
您有一个非锁定变量,您正在从另一个线程检查该变量。虽然
volatile
或 Interlocked.Read
等可以解决这个问题,但你并不需要所有这些搞乱任务和 Dispatcher
无论如何。
只需使用
CancellationToken
中止循环,然后使用 async
将循环置于 UI 线程上。
private CancellationTokenSource _stopMouseTracker = new();
public SubWindow()
{
InitializeComponent();
StartMouseTracker(_stopMouseTracker.Token);
}
private async Task StartMouseTracker(CancellationToken cancellationToken)
{
try
{
while (!cancellationToken.IsCancellationRequested)
{
var p = System.Windows.Forms.Cursor.Position;
// Write cursor coordinates to text box tbXY
tbXY.Text = $"{p.X} {p.Y}";
await Task.Delay(1, cancellationToken);
}
}
catch
{ //
}
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
stopMouseTracker.Cancel();
}