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()这是一个非常明显的错误!现在我明白了。谢谢这是一个非常明显的错误!现在我明白了。谢谢