代码是线程安全的?

时间:2016-06-20 19:42:34

标签: c# multithreading

我想知道这段代码是否安全?我想是的,因为引用类型是线程安全的,但在这种情况下,因为我们不能确定它是通用的吗?

 public class LifoMsgQueue<T>
    {
        private class Node<E>
        {
            internal Node<E> next;
            internal E msg;
            internal Node(E msg)
            {
                this.msg = msg;
            }
        }
        private Node<T> top;
        public void Send(T msg)
        {
            Node<T> node = new Node<T>(msg);
            node.next = top;
            top = node;
        }
        public T Receive()
        {
            SpinWait sw = new SpinWait();
            Node<T> oldTop;
            while ((oldTop = top) == null)
                sw.SpinOnce();
            top = oldTop.next;
            return oldTop.msg;
        }
    }

2 个答案:

答案 0 :(得分:4)

我认为,使代码线程安全的最简单方法是替换您的自定义&#34; LifoMsgQueue&lt; T&gt;&#34;使用System.Collections.Concurrent.ConcurrentStack&lt; T&gt;类,这将做同样的事情。

请参阅https://msdn.microsoft.com/en-us/library/dd267331(v=vs.110).aspx

  

表示线程安全的后进先出(LIFO)集合。

如果你想让你的类线程安全,那么你需要调查锁定机制,例如lock关键字。

答案 1 :(得分:3)

如果您有多个并发&#34;生产者&#34; (Send()的调用者)那么这绝不是安全的。两个线程可以看到相同的.top或race来覆盖它。

如果您有多个&#34;消费者&#34; (并不常见,但你并没有详细说明你寻求的安全程度,例如:1个消费者x 1生产者,1个消费者x N个生产者,N个消费者x 1个生产者,N个消费者x N个生产者)你是有可能重复邮件。

这里使用仿制药并不重要。虽然使用引用类型你不能搞砸读取(它们将是原子的,因为对象引用只是一个单词长,而Node是一个类),你很容易受到竞争条件的影响。

静态类Interlocked有许多工具可以缓解这些问题,如果您有兴趣自己实现它而不是依赖于IProducerConsumer工具。