2

Ich schreibe einen grundlegenden Firebase-Code in eine Xamarin iOS-App und stoße in eine klassische Deadlock-Situation mit einer TaskCompletionSource.TaskCompletionSource SynchronizationContext

public Task<string> GetUsers() 
{ 
    var tcs = new TaskCompletionSource<string>(); 
    _instance.GetChild("users").ObserveSingleEvent(DataEventType.Value, 
     x => { tcs.SetResult(x); }); 
    return tcs.Task; 
} 

Wenn ich auf diesem Code zu blockieren, wie so:

var users = GetUsers().Result; 

Die Anwendung Deadlocks.

Wenn ich richtig verstehe, versucht der Callback auf dem gleichen Kontext zu laufen, dass der .Result auf wartet.

Was ich nicht verstehe, ist, dass, wenn ich meinen Code modifizieren, um den GetUsers() Anruf in einem Task wie so erwarten:

var result = Task.Run(
    async() => await AppContext.Database.GetUsers().ConfigureAwait(false) 
).Result; 

Es ist noch Deadlocks.

Was passiert hier im zweiten Fall? Sollte nicht die Tatsache, dass der Code in einem anderen Thread aufgrund der Task.Run läuft, bedeuten, dass die Außenseite .Result den Callback-Aufruf nicht blockiert?

EDIT:

auf Nkosi Kommentar Nach oben Ich frage das, weil ich neugierig bin, warum der Code blockiert. Wenn ich auf den Anruf

var users = await GetUsers().ConfigureAwait(false); 

erwarte, dann geht der Deadlock weg. Ich möchte nur verstehen, warum es blockiert, wenn es in eine Task verpackt wird, weil basierend auf meinem (eindeutig inkorrekt) Verständnis von Task.Run, sollte es nicht.

+0

Für mich scheint dies ein XY-Problem zu sein. Zeigen Sie, was Sie letztlich in einem [mcve] erreichen wollen und vielleicht kann eine Lösung gelöst werden. Es sieht aus wie eine Mischung aus asynchronen und blockierenden Anrufen. also sollte auch der obere Aufrufstapel angezeigt werden. – Nkosi

+0

@Nkosi Ich bin eigentlich nicht fest, weil, wenn ich nur tun 'var users = erwarten Getusers(). ConfigureAwait (false)' dann läuft der Code ohne Deadlock. Ich bin nur neugierig, warum die 'Task.Run'-Version nicht funktioniert, weil sie auf meinem Verständnis basiert. –

+1

Ok. mein Missverständnis deiner Frage. Kennen Sie diesen Artikel von Stephen Cleary https://msdn.microsoft.com/en-us/magazine/jj991977.aspx – Nkosi

Antwort

3

ObserveSingleEvent sendet immer Rückruf an UI-Thread (und ich denke, alle oder fast alle Firebase-Callbacks tun das). Es erfasst nicht den Synchronisierungskontext oder etwas Ähnliches - sendet Callback immer nur an den UI-Thread (denken Sie daran - es ist nur ein Wrapper um nativen IOS-Code). Wenn Sie Ihren UI-Thread blockieren, indem Sie auf Result warten, wird dies aus offensichtlichen Gründen blockiert, unabhängig davon, von welchem ​​Thread Sie GetUsers aufrufen. Links, die Sie erwähnen, beschreiben eine andere Situation, in der aufgerufener Code den aktuellen Synchronisierungskontext erfasst, so dass sie den Code aus dem Hintergrundthread aufrufen, der keinen Synchronisierungskontext hat und Callbacks nicht an ihn gesendet werden. Das ist hier nicht der Fall.

Verwandte Themen