【问题标题】:SynchronizationContext.Post not working inside BackgroundWorkerSynchronizationContext.Post 在 BackgroundWorker 中不起作用
【发布时间】:2011-12-22 20:14:48
【问题描述】:

我正在使用后台工作人员来完成我的所有处理。在那里,我有很多地方可以写入“日志”文本框。所有这些工作都很好,但在后台工作人员的最后,最后一行,我通过SynchronizationContext 再打了一个电话,但没有触发。为什么所有其他调用都有效,而不是最后一个?

我应该补充一点,应用程序只是“挂起”,甚至还有一个 EventLog 条目说:

程序 MVST.CodeSync.exe 版本 2.0.0.0 停止与 Windows 交互并被关闭。 要查看有关问题的更多信息是否可用,请查看操作中心控制面板中的问题历史记录。 进程 ID:1f5c 开始时间:01ccc0e2e7ca1d42 终止时间:16 应用程序路径:C:\Users\ganders\Desktop\NewCodeSync\MVST.CodeSync.exe 报告 ID:629f3533-2cd6-11e1-9e15-005056b75254

这里是DoWork方法(调用RunWorkerAsync时执行):

private void bgw_StartCompare(object sender, DoWorkEventArgs e)
{
    OnWriteLogArgs args = null;
    CompareData compareData = e.Argument as CompareData;

    // We need to iterate through all of the nodes and if they are checked, continue
    foreach (TreeNode subSystemNode in compareData.TreeNodes)
    {
        if (!subSystemNode.Checked)
            continue;

        args = new OnWriteLogArgs(String.Format("-------------------------- Comparing sub-system: \"{0}\" with CompareType: \"{1}\" --------------------------", subSystemNode.Text, compareData.CompareType));
        syncContext.Post(delegate { OnWriteLog(args); }, null);

        // Each of these nodes should be a server, so continue
        foreach (TreeNode serverNode in subSystemNode.Nodes)
        {
            if (!serverNode.Checked)
                continue;

            args = new OnWriteLogArgs(String.Format("-------------------------- Comparing server: \"{0}\" with CompareType: \"{1}\" --------------------------", serverNode.Text, compareData.CompareType));
            syncContext.Post(delegate { OnWriteLog(args); }, null);

            // The "tag" contains the server information that we need to do the comparison
            CustomConfig.Server server = (CustomConfig.Server)serverNode.Tag;

            if (!compareData.DoneInitialCompare)
                CompareAll(compareData, server, string.Empty, server.CompareBasePath, serverNode, compareData.CompareType);
            else
                CompareAllByTreeNode(compareData, server, serverNode, compareData.CompareType);
        }
    }

    syncContext.Post(delegate { OnWriteLog(new OnWriteLogArgs("Finished the compare...")); }, null);

    RebuildTreeViewArgs rArgs = new RebuildTreeViewArgs(compareData.OnlyShowDifferences, compareData.TreeNodes);
    syncContext.Post(delegate { OnRebuildTreeView(rArgs); }, null);

    MessageBox.Show("It made it...");

    syncContext.Post(delegate { OnWriteLog(new OnWriteLogArgs("Finished calling the rebuild tree view method...")); }, null);
}

您会注意到在foreach 循环结束时,我写了Finished the compare...,并且确实写了,但是下一个同步调用:

     syncContext.Post(delegate { OnRebuildTreeView(rArgs); }, null);

永远不会被处决。方法如下:

private void OnRebuildTreeView(RebuildTreeViewArgs args)
{
    syncContext.Post(delegate { OnWriteLog(new OnWriteLogArgs("Made it to the OnRebuildTreeView method...")); }, null);

    while (bgw.IsBusy)
    {
        syncContext.Post(delegate { OnWriteLog(new OnWriteLogArgs("Sleeping...")); }, null);
        Thread.Sleep(1000);
    }

    syncContext.Post(delegate { OnWriteLog(new OnWriteLogArgs("Starting the rebuild of the TreeView...")); }, null);

    TreeNode[] tn = args.NewStructure;

    tvSync.Nodes.Clear();

    foreach (TreeNode node in tn)
        tvSync.Nodes.Add(node);

    foreach (TreeNode node in tvSync.Nodes)
        FixCheckedAndUnCheckedNodes(node);

    ReloadTreeView(args.OnlyShowDifferences);
}

【问题讨论】:

  • 如果 OnRebuildTreeView 已经在 GUI 线程中运行,为什么还要继续调用 syncContext完全有想法.. 我不知道这些是否使您的应用程序挂起,但它们看起来不太好。 .Post 也不会阻止调用者,如果您的逻辑需要阻止使用 .Send 而不是
  • 好点子,没想到从 OnRebuildTreeView 方法调用 syncContext ......我会拿出来的。至于 Thread.Sleep(),我只是添加了以防万一……(更多调试尝试)。我会删除那些东西,然后再试一次。谢谢
  • 如果您将OnRebuildTreeView 附加到RunWorkerCompleted 事件可能会使事情变得更简单,从您的代码看来,您似乎只想在线程的主要方法完成后执行它。
  • 我猜你的 syncContext 指的是 UI 线程。我认为您应该改用ReportProgress() 方法和ProgressChanged 事件。您是否尝试过在调试模式下逐步执行该方法?然后你会看到哪个方法挂了。
  • Matthias,我没有这样做,因为在 CompareAll() 和 CompareByTreeNode() 方法(从上面显示的 DoWork() 方法中调用)中,每个人都启动了线程正在比较的文件。所以 backgroundworker 正在运行,目录中的每个文件都有 1 个线程。我认为这会引起混乱,但也许不会。我花了大约 10 个小时将这个实用程序重新编写为多线程,不确定我是多么渴望回去“尝试”该配置。

标签: c# multithreading synchronization backgroundworker synchronizationcontext


【解决方案1】:
MessageBox.Show("It made it...");

也可能导致问题。因为这是在等待 UI 线程,而实际上是在后台线程上

【讨论】:

  • 我为了调试目的添加了它(看看它是否真的到达了那条线)。我刚把它拿出来,它仍然没有写出紧随其后的消息......
  • 使用System.Diagnostics.Debug.WriteLine() 进行调试。暗示 ui 的方法对于调试多线程应用程序是有害的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-19
  • 2023-03-03
  • 1970-01-01
  • 2021-11-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多