【问题标题】:Interlocked.CompareExchange "short-circuit" evaluationInterlocked.CompareExchange“短路”评估
【发布时间】:2015-11-14 02:08:06
【问题描述】:

我刚刚意识到我在Interlocked.CompareExchange 中分配了很多对象并将它们扔给GC,因为与使用@987654321 的&&|| 相比,总是评估值(第二个参数) @。

只有在目标位置是null 时,才能以原子方式检查 null 并分配新对象,锁定是唯一的替代方法吗?

这个测试打印了三遍“I am created”,最后一个断言失败了。

internal class TestCompareExchange {
    public static TestCompareExchange defalt = new TestCompareExchange();
    public static bool allocated = false;
    public TestCompareExchange() {
        allocated = true;
        Console.WriteLine("I am created");
    }
}

[Test]
public void CompareExchangeAllocatesValue() {

    if (TestCompareExchange.allocated && (new TestCompareExchange()) != null) // the second part after && is not evaluated 
    {

    }
    Assert.IsFalse(TestCompareExchange.allocated);

    TestCompareExchange target = null;
    var original = Interlocked.CompareExchange(ref target, new TestCompareExchange(), (TestCompareExchange)null);
    Assert.AreEqual(null, original);
    Assert.IsTrue(TestCompareExchange.allocated);

    TestCompareExchange.allocated = false;
    target = null;
    original = Interlocked.CompareExchange(ref target, new TestCompareExchange(), TestCompareExchange.defalt);
    Assert.AreEqual(null, original);
    Assert.IsFalse(TestCompareExchange.allocated); // no exchange, but objetc is allocated
}

在我的真实代码中,我使用TaskCompletionSource 而不是假对象。有关系吗?是否有一些 TCS 对象池化使得分配和收集与它们无关?

【问题讨论】:

  • 您考虑过使用Lazy<T>吗?
  • 如果另一个线程使用Interlocked.Exchange 将目标设置为nullLazy<T> 将如何提供帮助?
  • 据我了解,您只想拥有某个类的一个实例。 ... 仅当目标位置为 null 时自动检查 null 并分配新对象? Lazy<T> 就是这样做的。
  • 不,我只想在某个时间点拥有一个实例。每秒几百万次。这就像生产者-消费者,但生产者在消费者消费单个值之前永远不会产生值。

标签: c# .net task-parallel-library


【解决方案1】:

在执行Interlocked 操作和分配之前,请查看目标位置是否已经不为空。如果是,则无需尝试初始化。

if (Volatile.Read(ref target) == null) InitAtomically();

【讨论】:

  • 太好了,以前没用过Volatile 类。谢谢!这正是答案。
猜你喜欢
  • 1970-01-01
  • 2017-01-21
  • 2012-02-10
  • 2010-12-21
  • 1970-01-01
  • 2013-05-21
  • 2021-11-21
  • 2016-11-26
  • 2019-05-12
相关资源
最近更新 更多