Xamarin iOSアプリに基本的なFirebaseコードを書き、古典的なデッドロック状況である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;
}
私はそうのように、このコードをブロック:
var users = GetUsers().Result;
アプリケーションのデッドロック。
私が正しく理解している場合、コールバックは.Result
が待機しているのと同じコンテキストで実行しようとしています。
私は理解していないが、私はそうのようなTask
でGetUsers()
コールを待つために自分のコードを変更した場合ということです:
var result = Task.Run(
async() => await AppContext.Database.GetUsers().ConfigureAwait(false)
).Result;
それはまだデッドロック。
2番目のケースでは何が起こっていますか? Task.Run
のためにコードが別のスレッドで実行されているということは、外部の.Result
がコールバック呼び出しをブロックしないことを意味しますか?
EDIT:
は、私は、コードをブロックしている理由として興味ので、私はこれを聞いてるのよNkosiさんのコメントフォローアップ。電話を待つ場合
var users = await GetUsers().ConfigureAwait(false);
デッドロックがなくなります。私はちょうどTask
に包まれたときにブロックする理由を理解したいと思います。これは私の(明らかに間違った)理解に基づいてTask.Run
に基づいているので、そうしてはいけません。
私にとってこれはXY問題のようです。最終的に[mcve]で達成しようとしていることを示し、解決策が解決できるかもしれません。これは、非同期呼び出しとブロック呼び出しの混在のように見えます。上のコールスタックも同様に表示する必要があります。 – Nkosi
@Nkosi私はちょうど 'var users = Getusers()。ConfigureAwait(false)'を待っているとコードがデッドロックなしで実行されるので、実際には止まっていません。私は 'Task.Run'バージョンがなぜ私の理解に基づいて動作するのではないのか不思議です。 –
あなたの質問に対する私の誤解。あなたはStephen Clearyのこの記事に精通していますかhttps://msdn.microsoft.com/en-us/magazine/jj991977.aspx – Nkosi