使用 async/await 时如何避免 UI 线程上的竞争条件

我们都听说保持 UI 线程响应很重要,所以我们在任何地方实现 async/await。我正在构建一个文本编辑器,其中“一切”都是异步的。但是,现在我发现当代码在其他代码完成之前运行时,它会受到 UI 线程上的竞争条件的影响。当然,这就是“响应式 UI 线程”的全部思想,它可以运行代码,同时等待其他代码。我需要一些代码来等待其他代码在运行之前完成。我将问题归结为以下代码,我只是在其中处理击键:


    private async void Form1_KeyPress(object sender, KeyPressEventArgs e)

    {

        //Wait until it's your turn (await HandleKey has returned) before proceeding

        await HandleKey(e.KeyChar);

    }


    async Task HandleKey(char ch)

    {

        await GetCaretPosition();

        Point newPosition = await Task.Delay(1000);

        await SetCaretPosition(newPosition);

    }

正如您所看到的,当第一个键被处理(等待)时,下一个键可以开始处理。在这个简单的例子中,第二个键处理代码将获得一个旧的 caretposition 值,因为第一个键处理还没有更新 caretposition。如何让 KeyPress 事件中的代码等待第一个键完成处理?回到同步编码不是一种选择。


jeck猫
浏览 194回答 2
2回答

慕妹3242003

对于浏览此内容的任何人:这是我想出的,基于 k1dev 的链接SemaphoreSlim(在此处阅读。这实际上非常容易。根据问题中的代码,我添加了一个SemaphoreSlim并等待它(异步)。ASemaphoreSlim是一个轻量级的,Semaphore专门用于在 UI 线程上运行。我使用 aQueue<char>来确保以正确的顺序处理密钥:SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);Queue<char> queue = new Queue<char>();private async void Form1_KeyPress(object sender, KeyPressEventArgs e){&nbsp; &nbsp; queue.EnQueue(e.KeyChar);&nbsp; &nbsp; await semaphore.WaitAsync();&nbsp; &nbsp; try&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;await HandleKey(queue.DeQueue());&nbsp; &nbsp; }&nbsp; &nbsp; finally&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; semaphore.Release();&nbsp; &nbsp; }}作为奖励:我有一个方法,如果应用程序很忙,我只想跳过它,可以使用以下代码完成:if (await semaphore.WaitAsync(0)) //Note the zero as timeout{&nbsp; &nbsp; try&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;await MyMethod();&nbsp; &nbsp; }&nbsp; &nbsp; finally&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; semaphore.Release();&nbsp; &nbsp; }}

万千封印

首先,听起来这个问题还有更多内容,或者可能会有后续行动。也就是说,您可以尝试使您的 HandleKey 同步以管理共享资源:[MethodImpl(MethodImplOptions.Synchronized)]async Task HandleKey(char ch){试试这个线程以供参考: C# version of java's synchronized 关键字?PS - 所以我想得越多,你就越像是在尝试同步执行某些工作单元,但将其从 ui 线程中卸载。也就是说,同步 HandleKey 方法不会达到预期的结果。我认为您可能正在寻找 Dispatcher 模式:https://www.what-could-possively-go-wrong.com/the-dispatcher-pattern/https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher(v=vs.110).aspx
打开App,查看更多内容
随时随地看视频慕课网APP