任务完成源同步上下文

TaskCompletionSource SynchronizationContext

我正在 Xamarin iOS 应用程序中编写一些基本的 Firebase 代码,并且 运行 陷入典型的死锁情况 TaskCompletionSource

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;

它仍然死锁。

第二种情况是怎么回事?由于 Task.Run,代码在另一个线程上 运行 的事实不应该意味着外部 .Result 不会阻止回调调用吗?

编辑:

根据 Nkosi 的评论,我问这个问题是因为我很好奇为什么代码会阻塞。如果我等待电话

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

然后僵局就消失了。我只是想了解为什么它在包裹在 Task 中时会阻塞,因为根据我对 Task.Run 的(显然不正确的)理解,它不应该。

ObserveSingleEvent 总是将回调调度到 UI 线程(我认为所有或几乎所有的 firebase 回调都会这样做)。它不捕获同步上下文或类似的东西 - 只是总是将回调分派给 UI 线程(记住 - 它只是原生 IOS 代码的包装器)。因此,当您通过等待 Result 来阻塞 UI 线程时 - 出于明显的原因,无论您从哪个线程调用 GetUsers,它都会死锁。您提到的链接描述了另一种情况,当被调用代码捕获当前同步上下文时,它们从没有同步上下文的后台线程调用该代码,并且回调不会发布到它。这里不是这种情况。