C# 此BlockingQueue线程安全吗?
我试着实现一个最小的线程安全阻塞队列, 我想到的是:C# 此BlockingQueue线程安全吗?,c#,thread-safety,blockingqueue,C#,Thread Safety,Blockingqueue,我试着实现一个最小的线程安全阻塞队列, 我想到的是: class BlockingQueue<T> { private Queue<T> myQueue = new Queue<T>(); private SemaphoreSlim semaPhore = new SemaphoreSlim(0); public void Enqueue(T t) { lock(myQueue) {
class BlockingQueue<T>
{
private Queue<T> myQueue = new Queue<T>();
private SemaphoreSlim semaPhore = new SemaphoreSlim(0);
public void Enqueue(T t)
{
lock(myQueue)
{
myQueue.Enqueue(t);
semaPhore.Release();
}
}
public T Dequeue()
{
semaPhore.Wait();
lock(myQueue)
{
return myQueue.Dequeue();
}
}
}
类阻塞队列
{
专用队列myQueue=新队列();
私有信号量slim信号量=新信号量slim(0);
公共无效排队(T)
{
锁(myQueue)
{
myQueue.Enqueue(t);
semaPhore.Release();
}
}
公共T出列()
{
semaPhore.Wait();
锁(myQueue)
{
返回myQueue.Dequeue();
}
}
}
我试着对几个生产者和消费者同时进行压力测试,以随机的时间间隔排队,但没有失败
但是,如果我仔细查看代码,在“semaPhore.Wait()”和“lock(myQueue)”命令之间会发生什么事情吗?是的,可能会发生。。。
Thread.Abort()
将中断此队列
semaPhore.Wait();
// Here a Thread.Abort() happens
lock(myQueue) ...
然后发生的情况是,队列中有一个元素没有人能够恢复,因为与队列项目相比,有一个更少的“空闲”信号量插槽
除此之外(还有一个由专家在.NET4.0中编写的
BlockingCollection
),我会说代码是正确的semaPhore.Release()
会导致一个隐式障碍(因为它在内部使用了一个锁
),所以内存中的写入顺序没有问题(首先将真正完成Enqueue()
,然后将完成Release()
)。请注意,它将处于执行不良状态,因为每个操作需要两个锁(您的加上信号量lim
)中的一个。根据我现在提出的建议,令人惊讶的是,它使用的代码行更少:)
类阻塞队列
{
专用队列myQueue=新队列();
公共无效排队(T)
{
锁(myQueue)
{
myQueue.Enqueue(t);
Monitor.Pulse(myQueue);
}
}
公共T出列()
{
锁(myQueue)
{
Monitor.Wait(myQueue);
返回myQueue.Dequeue();
}
}
}
您是想学习如何编写阻塞队列
,还是为了工作?因为在.NET 4.0中有一个BlockingQueue
可能更合适?我投票将这个问题作为离题题来结束,因为它应该转移到CodeReview中。@AndreasNiedermair有一个具体的问题:但是,如果我仔细看代码,“semaPhore.Wait()”和“lock(myQueue)”之间会发生什么事情吗命令???@wonderb0lt OP怀疑代码中非常特定的部分可能无法按预期工作。这使得它脱离了代码审查的主题。正确,但Thread.Abort()会破坏很多东西。这很奇怪,我会明确地将其包含在这样一个队列的要求中。@HenkHolterman你说得很对。。。但是微软修改了<代码>监视器。只输入了<代码>线程。中止了<代码>(然后有趣地没有改变所有其他的同步对象……)所以如果我想考虑线程th.中止(),我应该走很长的路,类似于微软锁({)}。implementation@trykyn对您需要将信号量lim
(它在内部使用锁
,监视器.Pulse
…)与队列
和监视器.Wait And.Pulse的处理进行“合并”。您不需要额外的同步对象。确定,当Enqueue()和Pulse()之间发生线程.Abort()时会发生什么情况?
class BlockingQueue<T>
{
private Queue<T> myQueue = new Queue<T>();
public void Enqueue(T t)
{
lock(myQueue)
{
myQueue.Enqueue(t);
Monitor.Pulse(myQueue);
}
}
public T Dequeue()
{
lock(myQueue)
{
Monitor.Wait(myQueue);
return myQueue.Dequeue();
}
}
}