我试图在堆栈周围设计一个数据结构,直到堆栈有可用项为止。我尝试使用AutoResetEvent,但我想我误解了同步过程是如何工作的。基本上,看看下面的代码,当没有可用的时候,我尝试从堆栈中弹出。
似乎AutoResetEvent的行为就像一个信号量。对吗?我能不能摆脱BlockingStack.Get()中的BlockingStack.Get()并完成它呢?或者,这会导致我只使用堆栈项之一的情况。
public class BlockingStack
{
private Stack<MyType> _internalStack;
private AutoResetEvent _blockUntilAvailable;
public BlockingStack()
{
_internalStack = new Stack<MyType>(5);
_blockUntilAvailable = new AutoResetEvent(false);
for (int i = 0; i < 5; ++i)
{
var obj = new MyType();
Add(obj);
}
}
public MyType Get()
{
_blockUntilAvailable.WatiOne();
lock (_internalStack)
{
var obj = _internalStack.Pop();
if (_internalStack.Count > 0)
{
_blockUntilAvailable.Set(); // do I need to do this?
}
return obj;
}
}
public void Add(MyType obj)
{
lock (_internalStack)
{
_internalStack.Push(obj);
_blockUntilAvailable.Set();
}
}
}我的假设是,当通过AutoResetEvent函数调用时,所有等待的线程都会重置WaitOne()。然而,似乎多个线程正在进入。除非我把我的逻辑搞砸了。
编辑:这是用于Silverlight.的
发布于 2011-12-30 17:45:03
我没有验证基于Monitor的解决方案,但我确实编写了一个基于信号量的解决方案,该解决方案似乎正在工作:
public class Semaphore
{
private int _count;
private int _maximum;
private object _countGuard;
public Semaphore(int maximum)
{
_count = 0;
_maximum = maximum;
_countGuard = new object();
}
public void WaitOne()
{
while (true)
{
lock (_countGuard)
{
if (_count < _maximum)
{
_count++;
return;
}
}
Thread.Sleep(50);
}
}
public void ReleaseOne()
{
lock (_countGuard)
{
if (_count > 0)
{
_count--;
}
}
}
}
public class BlockingStack
{
private Stack<MyType> _internalStack;
private Semaphore _blockUntilAvailable;
public BlockingStack()
{
_internalStack = new Stack<MyType>(5);
_blockUntilAvailable = new Semaphore(5);
for (int i = 0; i < 5; ++i)
{
var obj = new MyType();
Add(obj);
}
}
public MyType Get()
{
_blockUntilAvailable.WaitOne();
lock (_internalStack)
{
var obj = _internalStack.Pop();
return obj;
}
}
public void Add(MyType obj)
{
lock (_internalStack)
{
_internalStack.Push(obj);
_blockUntilAvailable.ReleaseOne();
}
}
}发布于 2011-12-16 19:49:38
除非您只是想了解线程是如何工作的,否则最好使用阻塞集合。这将为您提供一个由堆栈支持的阻塞集合:
ConcurrentStack<SomeType> MyStack = new ConcurrentStack<SomeType>();
BlockingCollection<SomeType> SharedStack = new BlockingCollection<SomeType>(MyStack)然后,您可以以线程安全的方式访问它,所有阻塞都是为您正确完成的。请参阅这里
您可以通过调用sharedStack来使用sharedStack.Take(),然后调用sharedStack.Take()来阻塞抓取,直到堆栈中有需要获取的内容。
编辑:我花了一段时间(和两次尝试),但我想我已经解决了你的问题。
考虑一个空堆栈,其中有3个线程在等待事件。
调用Add时,堆栈有一个对象,并允许通过事件执行一个线程。
立即再次调用Add。
第一个线程现在等待从Add获取锁。
添加将第二个对象添加到堆栈中,并允许另一个线程通过该事件。
现在堆栈上的两个对象和事件中的两个线程,都在等待锁。
首先,Get线程现在使用锁和pops。仍然看到堆栈上的一个对象并调用设置。
第三个线程允许通过事件。
第二个Get线程现在使用锁和pops。看不到堆栈中的任何内容,也不调用set。
但。太晚了。第三个线程已经被允许通过,所以当第二个线程放弃锁时,第三个线程尝试从空堆栈弹出并抛出。
https://stackoverflow.com/questions/8539269
复制相似问题