处理异步/等待时的锁定行为

问题描述 投票:0回答:1

我可能想得太多了,但我不确定我是否理解在处理等待/异步时锁定是如何工作的。

考虑到以下情况,在每个

await
之后,不同的线程可以返回执行下一段代码,对吗? (除非在带有
TaskScheduler
的线程上运行,例如 WPF)

await Task.Run(async () =>
{
    // ThreadPoolWorker 1

    await Something();

    // ThreadPoolWorker 2

    await SomethingElse();

    // ThreadPoolWorker 3

    await SomethingElse2();

    // ThreadPoolWorker 4
});

考虑到这一点,我最终会不会遇到以下问题,我使用

Task.Run()
启动了两项任务。第一个任务进入
WaitAsync()
上的
Thread1
,因此
Thread1
拥有锁,但从另一个线程上的
WaitAsync
返回,例如
Thread 2

同时,在第二个

Task.Run()
中,
Thread 5
进入了
Task.Delay()
,但是当它从
await
返回时,理论上可能会在
Thread 1
上吗? ..所以现在不用等待锁了?

Task.Run(async () =>
{
    // Thread 1
    await semaphoreSlim.WaitAsync();
    // Thread 2
    
    ...
});

Task.Run(async () =>
{
    // Thread 5
    await Task.Delay(5000);
    // Thread 1
    await semaphoreSlim.WaitAsync();

    ...
});

我猜测处理此问题的方式是

await Semaphore.WaitAsync
必须始终在调用它的线程上返回?这是在 SemaphoreSlim 本身中实现的吗?

c# async-await locking task
1个回答
0
投票

如果有完整的代码示例,您的问题会更好,该代码示例具有输出和未满足的特定期望。

不过,我会尝试按照我的理解来回答。所以对于这段代码:

Task.Run(async () => // Task A
{
    // Thread 1
    await semaphoreSlim.WaitAsync();
    // Thread 2
});

Task.Run(async () => // Task B
{
    // Thread 5
    await Task.Delay(5000);
    // Thread 1
    await semaphoreSlim.WaitAsync();
});

您担心的是,两个任务同时运行,线程 1 执行第一个任务的前半部分,因此拥有信号量,可以绕过第二个等待?

这不会发生。请记住,任务是应按顺序执行的命令,并且可以由不同的线程执行,每次等待后由另一个线程接管。但是,这也意味着等待实际上并未在任何线程上完成。这样想吧:

  • 线程 1 开始执行任务 A 并遇到等待。信号量被阻塞,任务被搁置,因为此时它无法进一步执行。
  • 与此同时,线程 5 开始执行任务 B,并将其搁置一边,因为它在接下来的 5 秒内无法执行
  • 线程池空闲
  • 主线程调用Semaphore.Release()
  • 因此,任务 A 变得可执行,并且线程(线程 2)获取它并进一步运行它。
  • 计时器到期,任务 B 再次符合资格。线程 1 抓住它并继续。通过调用 WaitAsync(),任务需要再次被搁置。这是因为信号量知道它的状态并且它正忙。
  • 有人调用Release()
  • 任务 B 再次符合资格,并且某些线程可以拾取它

换句话来说,哪个线程启动 WaitAsync() 或哪个线程随后接管并不重要。重要的是,(完整的)信号量的释放将导致只有一个任务变得可执行,即使许多任务正在等待它。

© www.soinside.com 2019 - 2024. All rights reserved.