koalabruder
koalabruder

Reputation: 2904

How to avoid race conditions in BeginInvoke()?

I have a button in a browser frame (CEFSharp). If I click the button I can handle the click indirect with my C# method DoSomething(). DoSomething() is not called in the "Main-Thread". DoSomething() should call _api.CallAnExportedComFunction() in the "Main-Thread" (some functions in AutoCAD). _api.CallAnExportedComFunction() is an exported COM function. To call _api.CallAnExportedComFunction() in the "Main-Thread" I am using BeginInvoke(). _api.CallAnExportedComFunction() should not be called in parallel.

If I press the button one time everything works correct. If I press the button some times very slow everything works correct.

If I press the button very rapidly in a row _api.CallAnExportedComFunction() is called in parallel but it should not. I tried to use lock() inside of BeginInvoke but it does not work.

So Why is _api.CallAnExportedComFunction() called in parallel and how can I avoid it? Why have the Action's in BeginInvoke() race conditions? Does lock() only works between two DIFFERENT threads?

I am using the integer ix to count up and down. It should never reach the value 2. But it does. If I replace the COM-call _api.CallAnExportedComFunction() with an http request or a sleep it seems that I have no race-conditions.

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);
}

OUTPUT:
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

Unfortunatly I am not a COM expert and the COM code is not mine but If it is important I can try to add some code.

Upvotes: 0

Views: 140

Answers (0)

Related Questions