2

I have different scenario, than in this question, therefore another question.

Let's take following example:

void PerformanceCriticalMethod()
{
    Dispatcher.Invoke(() => Log.Add("1"));
    ... some job
    Dispatcher.Invoke(() => Log.Add("2"));
}

Invoke creates performance problems. In attempt to fix it I used InvokeAsync in place of Invoke and it seems to work, but it is important what 2 will be output after 1.

Can I rely on assumption what if two InvokeAsync are called from same thread they will execute in the same order? My winapi's nut tells me it's true, but I want to be sure.

And another related question is same as linked one: if same method is called via InvokeAsync action from different threads, how good are chances to have it executed first for thread who calls InvokeAsync earlier?

P.S.: I have feeling question should be rephrased "How InvokeAsync works", but the word "order" is probably 100% candidate of what people (including me) will try to search for.

Community
  • 1
  • 1
Sinatr
  • 20,892
  • 15
  • 90
  • 319

4 Answers4

1

Dispatcher.InvokeAsync() returns a DispatcherOperation object. It has a property Task:

Gets a T:System.Threading.Task that represents the current operation.

You can use all operations a Task supports. For example continue with the second dispatcher call.

Dispatcher.InvokeAsync(() => Log.Add("1")).Task.ContinueWith(() => {
    Dispatcher.InvokeAsync(() => Log.Add("2"));
});

As Yuval Itzchakov stated, if you simply want to execute them in order, you can await the InvokeAsync call, because DispatcherOperation is awaitable (since it exposes a GetAwaiter method).

Can I rely on assumption what if two InvokeAsync are called from same thread they will execute in the same order?

I would never rely on assumptions on the underlying system. It makes the system fragile (you never really know if that assumption is (still) true).

Domysee
  • 12,718
  • 10
  • 53
  • 84
  • I don't want to await for `InvokeAsync` at all. Is that even possible: 1) do not await 2) ensure in order of `InvokeAsync`? – Sinatr Sep 25 '15 at 08:56
  • If you want to ensure explicitly that `2` is executed after `1` and dont want to use await, you have to use a continuation (`Task.ContinueWith`). I dont see any other option. – Domysee Sep 25 '15 at 09:05
1

Please, check this out http://referencesource.microsoft.com/#WindowsBase/Base/System/Windows/Threading/Dispatcher.cs,1045

When you call InvokeAsync, an operation is put to PriorityQueue, so I suppose if you call several actions with the same priority, you can be confident that these actions will be executed with the same order.

olegk
  • 765
  • 4
  • 13
  • This answer is very close to what I want to know. Ok, it uses `PriorityQueue`, so it **must** come in same order (at least my hopes have confirmation now). But I see a `lock` there, what does it do? – Sinatr Sep 25 '15 at 08:51
  • Looks like that in case of multiple threads it will be executed with the same order due to this lock. – olegk Sep 25 '15 at 09:04
0

Dispatcher.InvokeAsync returns a DispatcherOperation, which is an awaitable (it exposes a GetAwaiter method). If you want to guarantee execution order, you can await them, in the desired order:

async Task PerformanceCriticalMethodAsync()
{
    await Dispatcher.InvokeAsync(() => Log.Add("1"));
    ... some job
    await Dispatcher.InvokeAsync(() => Log.Add("2"));
}
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • `await Dispatcher.InvokeAsync` is basically simple `Invoke` (which is costly), I want to avoid loosing time to do "some job", only ensure in right order. I can await for first invoke before doing next, but the problem what I will have **many invokes** (given example is simplified), so `await` is bad for me as it will eat time needed to wait until task is finished. And I don't want to wait. – Sinatr Sep 25 '15 at 08:48
  • @Sinatr You don't synchronously block with `await`. Control is yielded back to the caller, as the thread itself is freed. You're free to execute more work in the meanwhile. – Yuval Itzchakov Sep 25 '15 at 08:50
  • There is no caller. "Some job" part should run as soon as method is called and it's critical do not delay it with `Invoke`. I could use `queue` and producer/consumer, but my hope was what `InvokeAsync` already doing that. See @olegk answer. – Sinatr Sep 25 '15 at 08:54
  • @Sinatr I don't understand what you mean. *There is no caller* that makes no sense. If you want to start dealing with priorities, go right ahead. I think that will be more cumbersome to do. – Yuval Itzchakov Sep 25 '15 at 09:13
  • Sorry, let me explain: I don't want to make method async, because caller **can be** blocked. What I means as "no caller" is what I don't care about him (ofc every method is called by something). I only care about "some job" what has to be executed as soon as method is called. It shouldn't be delayed **and** `Log.Add` should be executed in same order **without** delaying "some job".. if possible. – Sinatr Sep 25 '15 at 09:25
0

I have made a conclusion for myself:

Whoever call InvokeAsync first will get its action serviced first.

It has nothing to do with normal async methods uncertainty "who will run first", because implementation of InvokeAsync is a pure thread-safe producer/consumer queue (can be seen in sources, thanks to @olegk answer).

Sinatr
  • 20,892
  • 15
  • 90
  • 319