C#异步/等待 - 限制异步方法的调用次数/锁定

10

我来自C++世界,因此我非常习惯于锁定线程和互斥保护。假设有这个基本函数:

async Task BasicProcess() {
    // await time consuming task
}

如何锁定此函数,以便仅允许同时运行一个 BasicProcess

这是我想要实现的目标:

async Task BasicProcess() {
    lock (BasicProcessLock) {
         // await time consuming task
    }
}

5
请参见http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx,以获取AsyncLock实现。 - Jon Skeet
1个回答

32
您可以使用 SemaphoreSlim(1) 来实现此目的。创建一个值为 1 的 SemaphoreSlim 将确保只有一个线程可以获取锁,任何试图获取锁的其他线程将等待直到已获得锁的线程释放它。
创建一个私有成员:
private SemaphoreSlim _syncLock = new SemaphoreSlim(1);

那么在你的代码中执行:

async Task BasicProcess() {

     await _syncLock.WaitAsync(); //Only 1 thread can access the function or functions that use this lock, others trying to access - will wait until the first one released.
     //Do your stuff..
     _syncLock.Release();

 }

4
除了这会阻塞调用线程,这并不理想,如果真的意味着要异步执行。 - Jon Skeet
最好使用“await _syncLock.WaitAsync();” - 否则,线程将被阻塞,任务也无法运行。 - jlahd
谢谢,这个好使。我之前也用了Wait(),但没有得到预期的结果。 - Grapes
8
把这个放在try/finally语句块中,对于保证安全也是有好处的。这样即使“// Do your stuff”抛出异常,你也能确保调用释放资源的方法。 - Brent
1
虽然这个解决方案可行,但它非常危险。信号量可能会被锁定很长时间。这对并发性能不利,也增加了死锁的机会。如果您想使用此解决方案,请确保始终使用 await _syncLock.WaitAsync() 进行线程同步。如果您使用同步等待,则当前线程可能会阻塞,异步操作无法再释放信号量(导致死锁)。所有需要同步的代码都应更改为异步方法,这将对您的代码产生相当大的影响! - Ramon de Klein
你在说什么?它是 await WaitAsync。 - ilansch

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