1

我正在使用以下代码来限制资源的使用。

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

我想知道我是否只限制 5 个线程进入这个 Get 方法,这是怎么发生的。

在调用 GetConnection 的地方,ReleaseConnection 也肯定是在 finally 块中调用的。

每次通话时,我也记录没有。队列中的资源。队列数似乎永远不会超过 5。

Semaphore smphSync = new Semaphore(0, 5);

Queue<IResource> resources;

private IResource GetResource()

{

    smphSync.WaitOne();

    IResource res = resources.Dequeue();

    return res;
}

private ReleaseResource(IResource res)

{

    resources.Enqueue(res);

    smphSync.Release();
}

我的问题是,我是否需要使用锁/监视器来同步对队列(资源实例)的访问?

4

2 回答 2

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();
}
于 2010-02-17T01:03:06.330 回答
1

我在我的ThreadSafeQueue类周围添加了 lock(),最近添加了一个 TryDequeue() 方法。更多细节在这篇文章中。绝对改进了我之前经常看到的多线程冲突(最明显的是当队列中不存在空值时返回空对象)。

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

于 2010-02-17T00:58:46.437 回答