为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
jeck猫 2021-11-21 16:30:53
我们都听说保持 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 事件中的代码等待第一个键完成处理?回到同步编码不是一种选择。
查看完整描述

2 回答

?
慕妹3242003

TA贡献1824条经验 获得超6个赞

对于浏览此内容的任何人:这是我想出的,基于 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)

{

    queue.EnQueue(e.KeyChar);

    await semaphore.WaitAsync();

    try

    {

       await HandleKey(queue.DeQueue());

    }

    finally

    {

        semaphore.Release();

    }

}

作为奖励:我有一个方法,如果应用程序很忙,我只想跳过它,可以使用以下代码完成:


if (await semaphore.WaitAsync(0)) //Note the zero as timeout

{

    try

    {

       await MyMethod();

    }

    finally

    {

        semaphore.Release();

    }

}


查看完整回答
反对 回复 2021-11-21
?
万千封印

TA贡献1891条经验 获得超3个赞

首先,听起来这个问题还有更多内容,或者可能会有后续行动。


也就是说,您可以尝试使您的 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


查看完整回答
反对 回复 2021-11-21
  • 2 回答
  • 0 关注
  • 193 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信