使用信号量保护队列的问题

时间:2010-02-17 00:53:55

标签: c# multithreading queue semaphore

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

偶尔(成功运行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();
}

我的问题是,我是否需要使用lock / Monitor同步对队列(资源实例)的访问?

2 个答案:

答案 0 :(得分: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();
}

答案 1 :(得分:1)

我在ThreadSafeQueue类附近添加了lock(),最近添加了一个TryDequeue()方法。 this post中的更多详细信息。绝对改进了我以前经常看到的多线程冲突(最值得注意的是,当队列中没有空值时返回一个空对象)。

修改:在TryDequeue()方法中检查并更新指向正确变更集的链接。