我正在使用以下代码来限制资源的使用。使用信号量来保护队列的问题
偶尔(成功运行3-4天后)我得到队列空异常或返回的对象被发现为空。
我想知道如果我限制只有5个线程进入这个Get方法,怎么会发生这种情况。
调用GetConnection的地方,ReleaseConnection也在Finally块中被明确调用。
随着每次通话,我也记录号码。的队列中的资源。队列计数似乎永远不会超过5.我的问题是,我需要使用锁定/监视器同步访问队列(资源实例)吗?
我正在使用以下代码来限制资源的使用。使用信号量来保护队列的问题
偶尔(成功运行3-4天后)我得到队列空异常或返回的对象被发现为空。
我想知道如果我限制只有5个线程进入这个Get方法,怎么会发生这种情况。
调用GetConnection的地方,ReleaseConnection也在Finally块中被明确调用。
随着每次通话,我也记录号码。的队列中的资源。队列计数似乎永远不会超过5.我的问题是,我需要使用锁定/监视器同步访问队列(资源实例)吗?
缺省情况下,标准.NET集合都不是线程安全的。他们不能同时访问没有某种内存屏障阻止并发访问。
在你的情况下,可以防止信号五年多线程访问resources
但没有什么能够阻止任何这五个并发线程从在同一时间进入或Dequeue()
Enqueue()
。在那些导致队列损坏的线程中发生罕见的竞争条件是完全可能的。你应该真的锁定resources
队列本身。
我还建议您在锁内执行测试以确保队列中仍有要删除的项目,然后再尝试拨打Dequeue()
。但是,由于我不知道代码的具体工作方式,因此我会将其留给您来决定是否相关。
Semaphore smphSync = new Semaphore(0, 5);
Queue<IResource> resources;
private _lockObj = new object();
private IResource GetResource()
{
smphSync.WaitOne();
lock(_lockObj)
{
IResource res = resources.Dequeue();
return res;
}
}
private ReleaseResource(IResource res)
{
lock(_lockObj)
{
resources.Enqueue(res);
}
smphSync.Release();
}
我在我的ThreadSafeQueue类中添加了lock(),并最近添加了TryDequeue()方法。更多详情,请参阅this post。绝对改进了多次线程碰撞,我之前经常看到(最明显的是当Queue中没有空值时返回空对象)。
编辑:检查TryDequeue()方法并更新链接到正确的变更集。
谢谢。其实,我正面临着完全相同的结果。 我已经加了锁,就像LBushkin说的那样。似乎工作。想要得到更好的理解。 – cdpnet
@cdpnet:不用担心。他的解决方案肯定会有帮助我的课程将提供相同的保护(更多使用TryDequeue()方法),而无需在任何地方重新编码锁。可能不是您提供的示例中的问题,但稍后可能会派上用场:-) –
太棒了!我很欣赏你的代码。我完成了完全相同的代码,似乎在过去几天工作。只是想确定我没有造成不必要的争论。 StackOverflow岩石。 – cdpnet
对于那些有兴趣的人,从.NET 4开始,框架包含System.Collections.Concurrent命名空间中的一些线程安全集合(http://msdn.microsoft.com/zh-cn/library/system.collections.concurrent% 28VS.100%29.aspx)。这包括一个无锁线程安全队列(ConcurrentQueue)。 – jeffora
@cdpnet:你有理由相信争用是一个问题吗?满足时锁通常只是昂贵的。我会永远锁定,只有当性能测试显示争用实际上是一个真正的问题时,我甚至会考虑尝试一个无锁解决方案。 –