首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AutoResetEvent与多集

AutoResetEvent与多集
EN

Stack Overflow用户
提问于 2011-12-16 19:37:23
回答 2查看 4K关注 0票数 6

我试图在堆栈周围设计一个数据结构,直到堆栈有可用项为止。我尝试使用AutoResetEvent,但我想我误解了同步过程是如何工作的。基本上,看看下面的代码,当没有可用的时候,我尝试从堆栈中弹出。

似乎AutoResetEvent的行为就像一个信号量。对吗?我能不能摆脱BlockingStack.Get()中的BlockingStack.Get()并完成它呢?或者,这会导致我只使用堆栈项之一的情况。

代码语言:javascript
复制
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.

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-12-30 17:45:03

我没有验证基于Monitor的解决方案,但我确实编写了一个基于信号量的解决方案,该解决方案似乎正在工作:

代码语言:javascript
复制
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();
        }
    }
}
票数 1
EN

Stack Overflow用户

发布于 2011-12-16 19:49:38

除非您只是想了解线程是如何工作的,否则最好使用阻塞集合。这将为您提供一个由堆栈支持的阻塞集合:

代码语言:javascript
复制
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。

但。太晚了。第三个线程已经被允许通过,所以当第二个线程放弃锁时,第三个线程尝试从空堆栈弹出并抛出。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8539269

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档