首页 > 解决方案 > 如何避免 BeginInvoke() 中的竞争条件?

问题描述

我在浏览器框架(CEFSharp)中有一个按钮。如果我单击按钮,我可以使用我的 C# 方法处理单击间接DoSomething()DoSomething()不在“主线程”中调用。DoSomething()应该调用_api.CallAnExportedComFunction()“主线程”(AutoCAD中的一些功能)。_api.CallAnExportedComFunction()是一个导出的 COM 函数。要调用_api.CallAnExportedComFunction()我正在使用的“主线程” BeginInvoke()_api.CallAnExportedComFunction()不应并行​​调用。

如果我按下按钮一次,一切正常。如果我按下按钮有时会非常慢,一切正常。

如果我连续快速按下按钮 _api.CallAnExportedComFunction()会被并行调用,但它不应该被调用。我尝试lock()在 BeginInvoke 内部使用,但它不起作用。

那么为什么要_api.CallAnExportedComFunction()并行调用,我该如何避免呢?为什么 BeginInvoke() 中的动作有竞争条件?是否lock()仅适用于两个不同的线程?

我正在使用整数 ix 向上和向下计数。它永远不应该达到值 2。但它确实如此。如果我用 http 请求或睡眠替换 COM 调用_api.CallAnExportedComFunction(),似乎我没有竞争条件。

private object _lock = new object();
private int ix = 0;

private void DoSomething()
{

    System.Diagnostics.Debug.WriteLine($"ThreadAny: {System.Threading.Thread.CurrentThread.ManagedThreadId}");

    // When initializing the Plugin _uiDispatcher.Dispatcher is set to System.Windows.Threading.Dispatcher.CurrentDispatcher
    _uiDispatcher.Dispatcher.BeginInvoke(new Action(() =>
    {
        lock (_lock)
        {
            ++ix;
            System.Diagnostics.Debug.WriteLine($"+ThreadMainBeginInvoke: {System.Threading.Thread.CurrentThread.ManagedThreadId} => ix={ix}");

            _api.CallAnExportedComFunction();

            //System.Threading.Thread.Sleep(1000);

            //var client = new System.Net.WebClient();
            //var b = client.DownloadData("http://www.google.de");

            --ix;
            System.Diagnostics.Debug.WriteLine($"-ThreadMainBeginInvoke: {System.Threading.Thread.CurrentThread.ManagedThreadId} => ix={ix}");

        }
    }), null);
}

输出
ThreadAny: 19
+ThreadMainBeginInvoke: 1 => ix = 1
-ThreadMainBeginInvoke: 1 => ix = 0
ThreadAny: 9
+ThreadMainBeginInvoke: 1 => ix = 1
ThreadAny: 27
+ThreadMainBeginInvoke: 1 => ix = 2
-ThreadMainBeginInvoke: 1 => ix = 1

不幸的是,我不是 COM 专家,COM 代码不是我的,但如果它很重要,我可以尝试添加一些代码。

标签: c#multithreadingcombegininvoke

解决方案


推荐阅读