c# – AutoResetEvent和多个集合

前端之家收集整理的这篇文章主要介绍了c# – AutoResetEvent和多个集合前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试围绕堆栈设计数据结构,直到堆栈有可用项目为止.我尝试使用AutoResetEvent,但我想我误解了同步过程是如何工作的.基本上,看下面的代码,我试图从没有可用的堆栈弹出.

似乎AutoResetEvent的行为类似于信号量.那是对的吗?我可以在BlockingStack.Get()中删除Set()并完成它吗?或者这会导致我只使用我的一个堆栈项目.

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

我的假设是当一个人通过WaitOne()函数调用时,AutoResetEvent会重置所有等待的线程.然而,似乎有多个线程进入.除非我在某处弄乱了我的逻辑.

编辑:这是为Silverlight.

解决方法

除非您只是想了解线程的工作原理,否则最好使用阻塞集合.这将为您提供由堆栈支持的阻塞集合:
ConcurrentStack<SomeType> MyStack = new ConcurrentStack<SomeType>();
BlockingCollection<SomeType> SharedStack = new BlockingCollection<SomeType>(MyStack)

然后,您可以以线程安全的方式访问它,并为您完成所有阻塞.见here

你可以通过调用sharedStack.Take()来使用sharedStack,然后它会阻塞,直到从栈中取出一些东西.

编辑:
花了一段时间(和两次尝试),但我认为我已经解决了你的问题.

考虑一个空堆栈,其中有3个线程在等待事件.

调用Add,堆栈有一个对象,允许一个线程通过事件.

立即添加再次调用.

第一个线程现在等待从Add获取锁定.

Add向堆栈添加第二个对象,并让另一个线程通过该事件.

现在堆栈上有两个对象,事件中有两个线程,两个都在等待锁定.

First Get线程现在需要锁定和弹出.在堆栈上看到一个对象仍然是CALLS SET.

第三个线程允许通过事件.

第二个Get线程现在需要锁定和弹出.在堆栈中看不到任何内容,也不会调用set.

但.太晚了.第三个线程已被允许通过,因此当第二个线程放弃锁定时,第三个线程会尝试从空堆栈弹出并抛出.

猜你在找的C#相关文章