- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试编写一个可以同时等待多个资源池的应用程序。每个资源池都由一个Semaphor
控制。我可以在传递整个信号量列表的地方使用 WaitHandle.WaitAll()
吗?此实现是否存在潜在的死锁问题?
我当前的实现:
namespace XXX
{
using System.Collections.Generic;
using System.Linq;
using System.Threading;
public class ResourcePoolManager
{
private readonly IDictionary<string, Semaphore> resourcePools = new Dictionary<string, Semaphore>();
public void AddResourcePool(string resourceName, int maxConcurrentConsumers)
{
this.resourcePools.Add(resourceName, new Semaphore(maxConcurrentConsumers, maxConcurrentConsumers));
}
public void RequestResource(string resourceName)
{
this.resourcePools[resourceName].WaitOne();
}
public void RequestMultipleResources(string[] resourceNames)
{
Semaphore[] resources = resourceNames.Select(s => this.resourcePools[s]).ToArray();
WaitHandle.WaitAll(resources);
}
public void ReleaseResource(string resourceName)
{
this.resourcePools[resourceName].Release(1);
}
}
}
最佳答案
当然,您可以使用它,但它只会在所有信号量同时触发时触发。根据应用程序其余部分的结构,可能确实存在饥饿问题。例如,如果您有两个资源 A 和 B,以及三个线程:
您可以很容易地等待 A 和 B 同时可用。
根据您的应用程序,简单地按顺序获取每个信号量可能会更好,这样可以避免这种饥饿问题,但会引入传统的死锁问题。但是,如果您确定这些锁在大多数时间都可用,那么它可能是安全的(但也可能是一个定时炸弹,只是在等待您的应用程序处于实际负载下...)
根据您的示例代码,另一种选择是对信号量创建全局排序 - 例如,按名称排序 - 并始终确保按该顺序获取它们。如果这样做,您可以通过按升序逐个锁定每个信号量来简单地执行多重锁定。
在这种情况下,释放顺序并不严格——但如果你乱序释放,你应该在你刚刚释放的锁“之后”释放所有锁,然后再获取任何锁(这是一个经验法则应该给你死锁安全。有可能通过详分割析进一步放松)。推荐的方法是尽可能以获取的相反顺序发布,在这种情况下,您可以随时将其转化为进一步的获取。例如:
只要一切都遵循这些规则,就不会出现死锁,因为不会形成等待者的循环。
这种方法的缺点是它可能会在等待另一个线程时持有锁,从而延迟其他线程。这不会永远持续下去;在上面的三个线程的例子中,我们可能会遇到这样的场景:
如您所见,有一些停机时间,线程 1 在 A 上被阻塞,即使没有真正的工作要做。但是,通过这样做,我们大大提高了线程 3 取得进展的机会。
这是否是一个好的权衡取决于您的应用程序 - 如果您可以明确地说多个线程永远不会进入锁,它甚至可能无关紧要。但是没有一种正确的方法:)
关于c# - 有没有办法等待多个信号量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/826769/
我是一名优秀的程序员,十分优秀!