gpt4 book ai didi

c# - 过度使用 Interlocked.exchange?

转载 作者:太空宇宙 更新时间:2023-11-03 17:26:08 26 4
gpt4 key购买 nike

我试图理解 Interlocked.Exchange 的正确用法,所以我正在实现一个简单的排序 LinkedList,具有添加和删除功能。

如果这不是一个线程安全列表,显然要找到插入点,您需要像下面这样的东西来找到正确的插入点然后插入新节点。

    public void Insert(int newValue)
{
var prev = _header;
Node curr = _header.Next;

while(curr != null && curr.value > newValue )
{
prev = curr;
curr = curr.Next;
}
var newNode = new Node(newValue, curr);
prev.Next = newNode;
}

下面是我对如何为并发列表执行此操作的看法。是否有太多 Interlocked.Exchange 正在进行?没有这个,插入仍然是线程安全的吗?成百上千个互锁操作会导致性能不佳吗?

    public void InsertAsync(int newValue)
{
var prev = _header;
Node curr = new Node(0, null);
Interlocked.Exchange(ref curr, _header.Next);

while (curr != null && curr.value > newValue)
{
prev = Interlocked.Exchange(ref curr, curr.Next);
}
//need some locking around prev.next first, ensure not modified/deleted, etc..
//not in the scope of this question.
var newNode = new Node(newValue, prev.Next);
prev.Next = newNode;
}

我知道,例如,curr = curr.next 是一个原子读取,但我可以确定特定线程将读取 curr.next 的最新值,而无需互锁吗?

最佳答案

使用 Interlocked 方法做两件事:

  1. 它执行一些通常不是原子操作的系列操作,并使它们有效地成为原子操作。在 Exchange 的情况下,你做的相当于: var temp = first;第一=第二; return temp; 但在执行此操作时不会有任何变量被另一个线程修改的风险。
  2. 它引入了内存屏障。编译器、运行时和/或硬件优化可能导致不同线程具有技术上位于共享内存中的值的本地“副本”(通常是缓存变量的结果)。这可能导致一个线程需要很长时间才能“看到”另一个线程中写入的结果。内存屏障实质上同步了同一变量的所有这些不同版本。

所以,具体到您的代码。您的第二个解决方案实际上不是线程安全的。每个单独的 Interlocked 操作都是原子的,但是对各种 Interlocked 调用的任意数量的调用都不是原子的。考虑到您的方法所做的一切,您的关键部分实际上要大得多;您需要使用 lock 或其他类似机制(即信号量或监视器)将对代码段的访问限制为仅单个线程。在您的特定情况下,我认为整个方法都是关键部分。如果你真的非常小心,你可能会有几个更小的关键 block ,但是很难确保不存在可能的竞争条件。

至于性能,嗯,因为代码不起作用,所以性能无关紧要。

关于c# - 过度使用 Interlocked.exchange?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12979416/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com