C# 由于竞争条件,车窗关闭不工作
这是我的密码:C# 由于竞争条件,车窗关闭不工作,c#,wpf,multithreading,race-condition,C#,Wpf,Multithreading,Race Condition,这是我的密码: private void OpenLoadingWindow() { loadingWindow = new LoadingView(); loadingWindow.Closed += new EventHandler(LoadingWindow_Closed); _go = true; loadingWindow.ShowDialog(); } public void OpenLoadingWindowInNewThread() {
private void OpenLoadingWindow()
{
loadingWindow = new LoadingView();
loadingWindow.Closed += new EventHandler(LoadingWindow_Closed);
_go = true;
loadingWindow.ShowDialog();
}
public void OpenLoadingWindowInNewThread()
{
thread = new Thread(x => OpenLoadingWindow());
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
lock (_locker)
{
Monitor.Pulse(_locker);
}
}
public void CloseLoadingWindow()
{
lock (_locker)
while (!_go)
Monitor.Wait (_locker);
if (loadingWindow != null)
{
loadingWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
{
_go = false;
loadingWindow.Close();
loadingWindow = null;
}));
}
}
在代码中,我首先调用OpenLoadingWindowInNewThread(),然后调用CloseLoadingWindow()。然而,第一次执行代码时,它工作正常。但在此之后,BeginInvoke中CloseLoadingWindow()中的代码不会执行。我做错了什么
我想要实现的是:打开加载窗口,执行一些代码。执行代码后,我调用closing方法,我想关闭加载窗口。这里的主要问题是您正在为UI创建第二个线程。不要那样做 不幸的是,您没有提供一个好的代码示例。为了回答这个问题,我们假设你正在做这样的事情:
void button1_Click(object sender, EventArgs e)
{
DoLoadingWork();
}
void DoLoadingWork()
{
OpenLoadingWindowInNewThread();
LoadingWork();
CloseLoadingWindow();
}
void DoLoadingWork()
{
using (LoadingView form = new LoadingView())
{
form.Shown += async (sender, e) =>
{
await Task.Run(() => LoadingWork());
form.Close();
};
form.ShowDialog();
}
}
也就是说,您的UI中发生了一些事件,现在您必须做一些工作。通过调用问题中显示的方法、在UI线程中处理工作并创建第二个线程来显示对话框,您实现了这一点
这是错误的做法。相反,您应该将所有UI保持在同一个线程中,并在不同的线程中进行工作。看起来更像这样:
void button1_Click(object sender, EventArgs e)
{
DoLoadingWork();
}
void DoLoadingWork()
{
OpenLoadingWindowInNewThread();
LoadingWork();
CloseLoadingWindow();
}
void DoLoadingWork()
{
using (LoadingView form = new LoadingView())
{
form.Shown += async (sender, e) =>
{
await Task.Run(() => LoadingWork());
form.Close();
};
form.ShowDialog();
}
}
此版本执行以下操作:
显示的事件,以确保对话框在任何其他事件发生之前可见
LoadingWork()
方法LoadingWork()
方法完成时,对话框关闭,允许释放对话框并返回DoLoadingWork()
方法Invoke()
进行UI交互(或者更好,重构处理过程,以便使用async
/await
,UI交互发生在工作的各个部分的await
语句之间)以及一个标志或CancellationToken
来处理线程中断
如果您的处理实际上与UI交互,并且您确实在UI线程中运行了它,那么很可能您调用了一些方法,如
Refresh()
或Application.DoEvents()
。这些方法实际上从来都不是必需的,IMHO总是代码实现不正确的标志。更改实现以将正确的代码放在正确的线程中的另一个好处是,您不必使用任何这些方法与UI交互(相反,您将使用Invoke()
)。您每次都打开一个单独的窗口吗?@YuvalItzchakov不,这是同一个窗口。不清楚您想要实现什么?如果你能解释的话,你可能会得到更好的答案。这根本不应该奏效。第一次成功可能只是运气。(整个)GUI不是线程安全的,您不能这样做。你不必这样做,线程是不需要的。调用线程应该是主线程,这应该是STA。