如何防止异步方法被重入?

3
我在程序中有一个异步方法。此任务需要异步,因为它执行网络请求,但我不希望它可重入。换句话说,如果该方法从代码块A调用,然后在第一次调用返回之前再次从代码块B调用,我希望第二个调用等待第一个调用完成后才运行。
如果该方法不是异步方法,我可以使用此注释实现: [MethodImpl(MethodImplOptions.Synchronized)]
然而,编译器不允许将该注释附加到异步方法。
我还能做什么?

你可以使用 SemaphoreSlim 这样的东西,以便只允许一个线程进入该方法。 - germi
“Synchronized”只是一个隐式的“lock”,虽然你不能在“async”方法中使用“lock”,但是存在像“SemaphoreSlim”和“AsyncLock”这样的东西,以异步方式实现互斥。另外,即使在同步代码中也要考虑不使用“Synchronized”——它基本上是因为Java有它而存在的,但它所做的隐式“lock (this)”比显式声明用于此目的的私有字段锁定要糟糕得多。 - Jeroen Mostert
1个回答

8

你可以使用 SemaphoreSlim,它是一种具有 WaitAsync 方法的锁(即使您在获取它的线程不同于释放时的线程也没有关系)。

private readonly SemaphoreSlim methodLock = new SemaphoreSlim(1, 1);

public async Task SomeMethod()
{
    await methodLock.WaitAsync();
    try
    {
        ...
    }
    finally
    {
        methodLock.Release();
    }
}

如果你想尝试一些冒险,你可以在 SemaphoreSlim 上编写一个扩展方法,使你能够做例如下的事情:
public async Task SomeMethod()
{
    using (await methodLock.WaitDisposableAsync())
    {
        ...
    }
}

注意: SemaphoreSlim 不支持递归(也无法支持)。这意味着如果你的方法是递归的,它将会死锁。


1
很酷,谢谢回复。我会尝试一下,听起来正是我需要的。 - Frank LaRosa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接