2010-02-17 31 views
1

我正在使用以下代码来限制资源的使用。使用信号量来保护队列的问题

偶尔(成功运行3-4天后)我得到队列空异常或返回的对象被发现为空。

我想知道如果我限制只有5个线程进入这个Get方法,怎么会发生这种情况。

调用GetConnection的地方,ReleaseConnection也在Finally块中被明确调用。

随着每次通话,我也记录号码。的队列中的资源。队列计数似乎永远不会超过5.我的问题是,我需要使用锁定/监视器同步访问队列(资源实例)吗?

回答

3

缺省情况下,标准.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(); 
} 
+0

太棒了!我很欣赏你的代码。我完成了完全相同的代码,似乎在过去几天工作。只是想确定我没有造成不必要的争论。 StackOverflow岩石。 – cdpnet

+1

对于那些有兴趣的人,从.NET 4开始,框架包含System.Collections.Concurrent命名空间中的一些线程安全集合(http://msdn.microsoft.com/zh-cn/library/system.collections.concurrent% 28VS.100%29.aspx)。这包括一个无锁线程安全队列(ConcurrentQueue)。 – jeffora

+2

@cdpnet:你有理由相信争用是一个问题吗?满足时锁通常只是昂贵的。我会永远锁定,只有当性能测试显示争用实际上是一个真正的问题时,我甚至会考虑尝试一个无锁解决方案。 –

1

我在我的ThreadSafeQueue类中添加了lock(),并最近添加了TryDequeue()方法。更多详情,请参阅this post。绝对改进了多次线程碰撞,我之前经常看到(最明显的是当Queue中没有空值时返回空对象)。

编辑:检查TryDequeue()方法并更新链接到正确的变更集。

+0

谢谢。其实,我正面临着完全相同的结果。 我已经加了锁,就像LBushkin说的那样。似乎工作。想要得到更好的理解。 – cdpnet

+1

@cdpnet:不用担心。他的解决方案肯定会有帮助我的课程将提供相同的保护(更多使用TryDequeue()方法),而无需在任何地方重新编码锁。可能不是您提供的示例中的问题,但稍后可能会派上用场:-) –