C#同步等待/轮询方法

时间:2010-08-01 07:17:34

标签: .net multithreading synchronization

我有一个暴露两种方法的类:

- GetObject

获取单个对象,如果没有,则返回null。

- WaitForObject

获取单个对象,或等到它们为1。

示例实现:

    class MyClass
    {
        MyStack stack;
        public object GetObject()
        {
            return stack.Pop();
        }
        public object WaitForObject()
        {
            object returnValue;
            while (returnValue == null)
                returnValue = stack.Pop()
            return returnValue
        }
    }

假设MyStack是线程安全的,我怎样才能使MyClass线程安全?即。

- GetObject永远不应该阻止 - 执行Thread的{​​{1}}应该将任何新对象添加到堆栈而不是WaitForObject

对于奖励积分,用户如何向堆栈添加对象,通知任何侦听器新对象可用? (无需轮询)

3 个答案:

答案 0 :(得分:1)

如果保证MyStack是线程安全的,那么MyClass也是线程安全的。在这两种方法中,您只使用局部变量,因此方法是可重入的。

目前,用户无法向堆栈添加对象,因为stack字段在类外部不可见。此外,我没有从您的代码中看到监听器如何订阅任何事件,以便在添加对象时通知他们。所以你可以有一个允许向堆栈添加元素的方法以及在这种情况下将触发的事件。

答案 1 :(得分:1)

我认为您可以使用Monitor功能实现一切。只是一个草图

class MyClass
{
    private Stack<object> stack = new Stack<object>();
    public object GetObject()
    {
        lock(stack)
        {
            return stack.Count != 0 ? stack.Pop() : null;
        }
    }
    public object WaitForObject()
    {
        lock (stack)
        {
            if (stack.Count == 0)
            {
                // wait until PutObject is called
                Monitor.Wait(stack);
            }

            return stack.Pop();
        }
    }

    public void PutObject(object obj)
    {
        lock (stack)
        {
            stack.Push(obj);
            // notify one thread blocked by WaitForObject call
            Monitor.Pulse(obj);
        }
    }
}

答案 2 :(得分:0)

轮询通常涉及某种形式的睡眠 - 你的例子中的循环将是一个紧密的循环,它会一直扼杀thead。添加Thread.Sleep(100)来电或其他合理值,以便随着时间的推移进行投票。

另一种等待的方法是注册一个回调,或让堆栈公开一个阻塞Pop方法,无论哪种方式,这些都将在你的例子中的Stack类中实现。

奖励答案:您的类需要公开一个事件,当他们将一个对象添加到堆栈时,它会触发此事件。

class MyClass 
    { 
        MyStack stack; 
        public object GetObject() 
        { 
            return stack.Pop(); 
        } 
        public object WaitForObject() 
        { 
            object returnValue; 
            while (returnValue == null) 
                returnValue = stack.Pop() 
            return returnValue 
        } 
        public void AddObject(object o)
        {
            stack.Push(o);
            OnObjectAdded();
        }
        public event EventHandler ObjectAdded;

        private void OnObjectAdded()
        {
            if (ObjectAdded != null)
                ObjectAdded(this, EventArgs.Empty);
        }
    }