我想知道这段代码是否安全?我想是的,因为引用类型是线程安全的,但在这种情况下,因为我们不能确定它是通用的吗?
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;
}
}
答案 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工具。