簡體   English   中英

SynchronizationLockException: 無法在此運行時上等待監視器。 - Blazor wasm 中 TaskCompletionSource 的解決方法

[英]SynchronizationLockException: Cannot wait on monitors on this runtime. - Workaround for TaskCompletionSource in Blazor wasm

我有一個異步方法,它返回輸入表單的輸入用戶值。 只要用戶沒有提交輸入,異步方法Task<String> Read()應該等待。 當用戶提交輸入表單時,方法Task Execute(EditContext context)被觸發。 因此,只要表單未提交,我就使用TaskCompletionSource來阻止Read方法(這適用於 wpf 應用程序,我做到了)。


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:無法等待此運行時上的監視器。 at (wrapper managed-to-native) System.Threading.Monitor.Monitor_wait(object,int) at System.Threading.Monitor.ObjWait (System.Boolean exitContext, System.Int32 millisecondsTimeout, System.Object obj) <0x2e64fc8 + 0x00046>在 :0 在 System.Threading.Monitor.Wait (System.Object obj, System.Int32 毫秒超時, System.Boolean exitContext) <0x2e64ce8 + 0x00022> 在 :0 在 System.Threading.Monitor.Wait (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 上有很多類似的問題。

順便說一下,如果您從 UI 線程執行Read().GetAwaiter().GetResult() ,WPF 中也會發生同樣的情況。 不一樣,因為在 WPF 的情況下它只會死鎖,但“不會工作”。

所以一路異步,永遠不要阻塞主線程,因為它是你唯一的線程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM