c# - SynchronizationLockException:无法等待此运行时的监视器。- Blazor wasm 中 TaskCompletionSource 的解决方法
问题描述
我有一个异步方法,它返回输入表单的输入用户值。只要用户没有提交输入,异步方法Task<String> Read()
就应该等待。当用户提交输入表单时,该方法Task Execute(EditContext context)
被触发。因此,只要未提交表单,我就使用TaskCompletionSource
来阻止该方法(这适用于 wpf 应用程序,我做到了)。Read
public async Task<String> Read()
{
StringReadTaskCompletionSource = new TaskCompletionSource<string>();
return await StringReadTaskCompletionSource.Task;
}
protected Task Execute(EditContext context)
{
//...
StringReadTaskCompletionSource
.SetResult((context?.Model as ConsoleInput as ConsoleInput).Text);
}
但是通过上面的代码,我得到:
暴击:Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] 未处理的异常渲染组件:无法等待此运行时的监视器。System.Threading.SynchronizationLockException:无法等待此运行时的监视器。在(包装器托管到本机) System.Threading.Monitor.Monitor_wait(object,int) 在 System.Threading.Monitor.ObjWait (System.Boolean exitContext, System.Int32 毫秒超时, System.Object obj) <0x2e64fc8 + 0x00046>在 System.Threading.Monitor.Wait 的 :0 (System.Object obj, System.Int32 毫秒超时, System.Boolean exitContext) <0x2e64ce8 + 0x00022> 在 System.Threading.Monitor.Wait 的 :0 (System.Object obj, System .Int32 毫秒超时)
它看起来像是 razor-wasm 对任务和线程的限制的结果。我从这里尝试了解决方法:https ://github.com/dotnet/aspnetcore/issues/14253#issuecomment-534118256
通过使用 Task.Yield 但不成功。知道如何解决这个问题吗?
[编辑:] 我认为对我来说主要结论是,使用 razor-wasm(由于一个线程限制)运行同步方法(Console.ReadLine()
)并等待用户输入而不阻塞整个应用程序是不可能的。看起来没有解决方法。唯一的方法是将所有这些同步调用替换为新的异步调用,例如Console.ReadLineAsync()
.
解决方案
我通过您提供的 github 链接检查了代码,并注意到您正在这样做:
_stringReaderRedirect = new StringReaderRedirect(Read);
Read
有问题的功能在哪里。然后在里面StringReaderRedirect
你有:
private readonly Func<Task<string>> _ReadRedirectFunc;
public StringReaderRedirect(Func<Task<string>> readredirect) : base("foo")
{
_ReadRedirectFunc = readredirect;
}
然后你这样做:
public override string ReadLine()
{
//return _ReadRedirectFunc?.Invoke();
//return base.ReadLine();
Task<string> task = _ReadRedirectFunc?.Invoke();
return task?.GetAwaiter().GetResult();
}
所以你阻塞了异步调用,这是有问题的异常的来源。在像 Blazor WASM 这样的单线程环境中,这样做是一个主要的禁忌。如果您看到的异常没有被抛出,那么您将遇到死锁:唯一的线程(UI)被阻塞等待结果Read
,而Read
它本身取决于用户输入,需要哪个 UI 线程。blazor github repo 上有很多类似的问题,例如.
Read().GetAwaiter().GetResult()
顺便说一句,如果您从 UI 线程中进行操作,那么 WPF 中也会发生同样的情况。不一样,因为在 WPF 的情况下,它只会死锁,但也“不起作用”。
所以一直异步,永远不要阻塞主线程,因为它是你唯一的线程。
推荐阅读
- c# - MAGELLAN 8500XT 中的实时秤
- wcf - WCF 不支持可选参数
- python - 我正在尝试在 python 中使用 HTML img 标签发送邮件,但出现以下错误
- javascript - BIRT eclipse - 删除列中的重复值 - ROWSPAN
- mysql - MySQL Query 不适用于所有测试用例
- reactjs - react native 中架构 armv7 的 1 个重复符号
- google-chrome - 无法向公众发布 chrome 扩展
- scope - 递归调用的变量是自由的还是绑定的?
- visual-studio-code - VSCode - 是否有任何选项可以替换 vs 代码中单引号内的任何形式的文本?
- python - 在 jupyter notebook 中以原始分辨率显示图像