同一个锁中的几个线程

时间:2012-07-25 06:12:37

标签: c# .net multithreading

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

这是我的队列:

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;
        }
    }
}

这是我使用它的部分(工作是一个线程函数):

private readonly SafeQueue<string> taskQueue = new SafeQueue<string>();
private volatile bool stop = false;
...
 private void Work()
    {
        while ( !stop )
        {
            string dir = null;
            if (taskQueue.Count > 0)
            {
                dir = taskQueue.Dequeue();
            }
...

所以,问题基本上是:两个线程获取Count属性的锁并返回一个正值。因为他们都试图将一个元素出列。

1 个答案:

答案 0 :(得分:4)

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

通过这样的操作,您的代码变为:

while ( !stop )
{
    string dir;
    if(taskQueue.TryDequeue(out dir))
    {
    }

您的调试打印也可能会产生误导。您只能在实际解锁后的某个时间打印“未锁定”行。因此,在实际解锁和调试输出之间,不同的线程可能会进入锁定并打印其“锁定”行,从而导致输出混乱。

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