C# 同步等待/轮询方法

发布于 2024-09-12 11:47:38 字数 1236 浏览 4 评论 0原文

我有一个公开两个方法的类:

 - GetObject

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

 - WaitForObject

获取单个对象,或等待直到它们成为一个对象。

示例实现:

     

    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 执行 WaitForObject 应该将任何新对象添加到堆栈中,而不是 GetObject

为了获得奖励积分,向堆栈添加对象的用户如何通知任何侦听器有新对象可用? (消除了轮询的需要)

I have a class that exposes two methods:

 - GetObject

Gets a single object, or returns null if there are none.

 - WaitForObject

Gets a single object, or waits until their is one.

An example implementation:

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

With the assumption that MyStack is thread safe, how can I make MyClass thread safe? I.e.

 - GetObject should never block
 - Thread doing WaitForObject should get any new objects added to the stack instead of GetObject.

For bonus points, how can users adding objects to the stack notify any listeners that a new object is available? (eliminating the need for polling)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

甜嗑 2024-09-19 11:47:38

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

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

If MyStack is guaranteed to be thread safe then MyClass is also thread safe. In the two methods you are using only local variables so the methods are reentrant.

Currently users cannot add objects to the stack because the stack field is not visible outside the class. Also I don't see from your code how do listeners will subscribe to any events so that they are notified if an object is added. So you could have a method allowing to add elements to the stack and an event that will be triggered in this case.

救星 2024-09-19 11:47:38

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

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

I think that you can achieve everything with Monitor functionality. just a sketch

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);
        }
    }
}
叹梦 2024-09-19 11:47:38

轮询通常涉及某种形式的睡眠 - 您的示例中的循环将是一个紧密的循环,会一直限制头部。添加 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);
        }
    } 

Polling usually involves some form of sleep - the loop in your example would be a tight loop that would throttle the thead all the time. Add a Thread.Sleep(100) call, or some other sensible value, to poll over time.

The other way to wait would be to register a callback, or have the stack expose a blocking Pop method, either way, these would be implemented in the Stack class in your example.

Bonus Answer: Your class would need to expose an event, when they add an object to the stack, it would fire this event.

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);
        }
    } 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文