Is nesting either one of these inside the other bad? In the past, I had a hanging/deadlock issue that I could reproduce when doing the top block of code, and I could NOT reproduce when I changed it to the bottom block of code... I really didn't understand it at the time, and I still don't. Is there something about the combination of Lock & InvokeOnMainThread that I should know about? I could provide more details about what I'm doing, but this is more of a general question than anything...

Let's say I want to "DoStuff" in a background thread. And I have a variable that is accessed from multiple threads.

lock( stuff )
{
    InvokeOnMainThread ( delegate {
        stuff.DoStuff();
    });
}

Alternate

InvokeOnMainThread ( delegate {
    lock( stuff )
    {
        stuff.DoStuff();
    }
});

Added information: I have an iOS application with a connection manager function that runs in a background thread. The connection manager function is responsible for keeping alive and managing an asynchronous network socket connection. There are many instances where I need to InvokeOnMainThread when doing things or else I'll get the following error "UIKit Consistency error: you are calling a UIKit method that can only be invoked from the UI thread."

有帮助吗?

解决方案

The difference between the two is that second block of code will not prevent anything from being executed on the executing thread before you DoStuff.

Example:

 lock (stuff) {
     InvokeOnMainThread ( delegate { Console.WriteLine ("a"); } }
 }
 Console.WriteLine ("b");

will print:

a
b

while this code:

 InvokeOnMainThread ( delegate {
    lock (stuff) {
        Console.WriteLine ("a");
    }
 }
 Console.WriteLine ("b");

will usually (but not necessarily) print:

b
a

Now this doesn't explain why the second block would fix the race condition, but my guess would be that it would just change the race condition enough for you to not hit it again (so not fix it, just hide it).

其他提示

So if we assume that this is only method where you are using lock(stuff) only logical explanation why is first case causing you deadlock is that thread A(background thead) comes to this method and go inside lock(stuff). So now stuff is locked on thread A. Now thread A invokes MainThread and if you call this method from stuff.DoStuff() you will get deadlock because MainThread will run into lock(stuff) and it will wait until thread A releases lock(stuff) but Thread A will release when MainThread is done with invocation... Resulting in deadlock.

There is also possibility with first case even if you don't call this method from stuff.DoStuff() from anywhere on MainThread deadlock occurs only difference is that InvokeOnMainThread is not executing stuff.DoStuff() yet but it's only queued to execute on MainThread resulting in same deadlock situation.

Now with second example where lock(stuff) is inside InvokeOnMainThread there is no chance deadlock occurs because lock(stuff) is doing it only on MainThread so it has no functionality so you can remove it. Because executing code on MainThread is 100% synchronous "locked" already.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top