C# 同一锁中的多个线程

C# 同一锁中的多个线程,c#,.net,multithreading,C#,.net,Multithreading,我正在尝试为常规队列类实现线程安全包装器。但似乎几个线程可能获得相同的锁。所以我的问题是: 1.怎么可能呢? 2.如何避免它? 3.任何有用的建议我都很高兴 这是我的队列: public class SafeQueue<T> : SimpleQueue<T> { private readonly object sync = new object(); private readonly Queue<T> queue = new Queue<

我正在尝试为常规队列类实现线程安全包装器。但似乎几个线程可能获得相同的锁。所以我的问题是:
1.怎么可能呢?
2.如何避免它?
3.任何有用的建议我都很高兴

这是我的队列:

public class SafeQueue<T> : SimpleQueue<T>
{
    private readonly object sync = new object();
    private readonly Queue<T> queue = new Queue<T>();

    public override T Dequeue()
    {
        T item;
        lock (sync)
        {
            Debug.Print("{1:mm ss ffff} {0} locked in dequeue", Thread.CurrentThread.ManagedThreadId, DateTime.Now);
            item = queue.Dequeue();
        }
        Debug.Print("{1:mm ss ffff} {0} unlocked dequeue", Thread.CurrentThread.ManagedThreadId, DateTime.Now);
        return item;

    }

    public override void Enqueue(T item)
    {
        lock (sync)
        {
            queue.Enqueue( item );
        }
    }

    public override IEnumerator<T> GetEnumerator()
    {
        Queue<T> q;
        lock (sync)
        {
            q = new Queue<T>(queue);
        }

        return ((IEnumerable<T>) q).GetEnumerator();
    }

    public override int Count
    {
        get
        {
            int c;
            lock (sync)
            {
                Debug.Print("{1:mm ss ffff} {0} locked in count", Thread.CurrentThread.ManagedThreadId, DateTime.Now);
                c = queue.Count;
            }
            Debug.Print("{1:mm ss ffff} {0} unlocked count. Ret {2}", Thread.CurrentThread.ManagedThreadId, DateTime.Now,c);
            return c;
        }
    }
}
公共类安全队列:SimpleQueue
{
私有只读对象同步=新对象();
私有只读队列队列=新队列();
公共覆盖T退出队列()
{
T项;
锁定(同步)
{
Print(“{1:mm ss ffff}{0}在出列时被锁定”,Thread.CurrentThread.ManagedThreadId,DateTime.Now);
item=queue.Dequeue();
}
Print(“{1:mm ss ffff}{0}解锁出队列”,Thread.CurrentThread.ManagedThreadId,DateTime.Now);
退货项目;
}
公共覆盖无效排队(T项)
{
锁定(同步)
{
排队。排队(项目);
}
}
公共重写IEnumerator GetEnumerator()
{
队列q;
锁定(同步)
{
q=新队列(队列);
}
return((IEnumerable)q.GetEnumerator();
}
公共覆盖整数计数
{
得到
{
INTC;
锁定(同步)
{
打印(“{1:mm ss ffff}{0}锁定计数”,Thread.CurrentThread.ManagedThreadId,DateTime.Now);
c=队列计数;
}
Print(“{1:mm ss ffff}{0}unlocked count.Ret{2}”,Thread.CurrentThread.ManagedThreadId,DateTime.Now,c);
返回c;
}
}
}
这是我使用它的地方(Work是一个线程函数):

private readonly SafeQueue taskQueue=new SafeQueue();
私有易失性bool-stop=false;
...
私人工作()
{
当(!停止)
{
字符串dir=null;
如果(taskQueue.Count>0)
{
dir=taskQueue.Dequeue();
}
...

因此,问题基本上是:两个线程获取lock on Count属性并返回一个正值。因此,它们都试图将一个元素出列。

一个明显的错误是,在您检查计数和相关的
出列之间可能有一个项目出列。因此,线程安全队列通常具有原子属性<代码>TryDequeue
操作

通过此操作,您的代码将变为:

while ( !stop )
{
    string dir;
    if(taskQueue.TryDequeue(out dir))
    {
    }
调试打印也可能会产生误导。您只会在实际解锁发生后的一段时间打印“解锁”行。因此,在实际解锁和调试输出之间,不同的线程可能会进入锁并打印其“锁定”行,从而导致输出混乱


.net有两个内置的线程安全队列:
ConcurrentQueue
,它是非阻塞的,
BlockingCollection
,它是阻塞的。

一个明显的错误是,在您检查计数和相关的
dequeue
之间可能有一个项目出列。因此,线程安全队列通常有一个原子
TryDequeue
操作

通过此操作,您的代码将变为:

while ( !stop )
{
    string dir;
    if(taskQueue.TryDequeue(out dir))
    {
    }
调试打印也可能会产生误导。您只会在实际解锁发生后的一段时间打印“解锁”行。因此,在实际解锁和调试输出之间,不同的线程可能会进入锁并打印其“锁定”行,从而导致输出混乱


.net有两个内置的线程安全队列:
ConcurrentQueue
,它是非阻塞的,
BlockingCollection
,它是阻塞的。

两个不同的线程永远不能进入同一个锁。还有一些事情正在发生。@CodesInChaos说的。如果是.net 4,则有ConcurrentQueue()两个不同的线程永远无法进入同一个锁。发生了其他事情。@CodesInChaos说的。如果是.net 4,则会出现ConcurrentQueue()这是一个非常明显的错误!现在我明白了。谢谢这是一个非常明显的错误!现在我明白了。谢谢