我创建了一个“Manager”类,其中包含一组有限的资源。资源作为队列存储在“Manager”中。我将Queue和Semaphore初始化为相同的大小,如果没有可用的资源,使用信号量来阻塞线程。我有多个线程调用此类来请求资源。这是伪代码:
public IResource RequestResource()
{
IResource resource = null;
_semaphore.WaitOne();
lock (_syncLock)
{
resource = _resources.Dequeue();
}
return resource;
}
public void ReleaseResource(IResource resource)
{
lock (_syncLock)
{
_resources.Enqueue(resource);
}
_semaphore.Release();
}
在运行此应用程序时,它似乎运行良好一段时间。然后,似乎我的队列正在发出相同的对象。这看起来有可能吗?我把头发拉到这里,任何帮助都会非常感激。如果需要,请随时询问更多信息。谢谢!
答案 0 :(得分:2)
信号量在这里是偶然的;这只会限制可以同时获取资源的消费者数量。同步实际上来自lock
语句(关键部分)。
据我所知,该代码是线程安全的。当你说它是“给出相同的对象”时 - 也许我误解了这个问题,但它应该给出相同的对象,因为当调用者调用Release
方法时,放回他们最初获得的相同资源,因此在执行期间,同一个对象将在队列中的几个点上。
如果你的意思是RequestResource
方法正在返回已经获得但尚未发布的资源,那么我只能想到三个可能的原因:
队列从头开始包含重复的资源;
消费者两次调用Release
方法。在Release
方法中,您实际上并未检查资源是否已经回到队列中;您可能希望更改此代码以检查此并抛出异常,这将有助于您捕获Release
调用被复制的位置(如果实际情况如此)。
其他一些代码在没有_resources
的情况下访问lock
队列。
我的怀疑是#2,如果这确实是你重复的意思。
答案 1 :(得分:0)
除了Aaronaught的回答:
两个线程完全有可能获取信号量,然后一个线程进入RequestResource()
中的关键部分,另一个块,然后是第一个线程完成其所有工作并将对象返回到在第二个线程唤醒并有机会出列之前,ReleaseResource()
的队列。这会给两个线程获得相同对象的印象。