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();
    }
}
此版本执行以下操作:

  • 在UI线程中创建状态对话框
  • 订阅
    显示的
    事件,以确保对话框在任何其他事件发生之前可见
  • 显示对话框
  • 显示该对话框后,将启动一个新线程来执行
    LoadingWork()
    方法
  • LoadingWork()
    方法完成时,对话框关闭,允许释放对话框并返回
    DoLoadingWork()
    方法
  • 请注意,即使您必须通过执行处理的代码与UI交互,或者如果您需要一种中断处理的方法,上述方法仍然是正确的方法。这些需求的其他方面可以很容易地实现,使用标准的习惯用法来处理它们

    如果没有一个实际的例子来说明该处理可能是什么,以及UI交互和/或中断是如何工作的,那么就不可能确切地说出该部分将如何实现。但它通常涉及使用
    Invoke()
    进行UI交互(或者更好,重构处理过程,以便使用
    async
    /
    await
    ,UI交互发生在工作的各个部分的
    await
    语句之间)以及一个标志或
    CancellationToken
    来处理线程中断


    如果您的处理实际上与UI交互,并且您确实在UI线程中运行了它,那么很可能您调用了一些方法,如
    Refresh()
    Application.DoEvents()
    。这些方法实际上从来都不是必需的,IMHO总是代码实现不正确的标志。更改实现以将正确的代码放在正确的线程中的另一个好处是,您不必使用任何这些方法与UI交互(相反,您将使用
    Invoke()
    )。

    您每次都打开一个单独的窗口吗?@YuvalItzchakov不,这是同一个窗口。不清楚您想要实现什么?如果你能解释的话,你可能会得到更好的答案。这根本不应该奏效。第一次成功可能只是运气。(整个)GUI不是线程安全的,您不能这样做。你不必这样做,线程是不需要的。调用线程应该是主线程,这应该是STA。