简体   繁体   English

互锁。比较交换“短路”评估

[英]Interlocked.CompareExchange “short-circuit” evaluation

I have just realized that I allocate a lot of objects in Interlocked.CompareExchange and throw them away to GC, because the value (second argument) is always evaluated, compared to && or || 我刚刚意识到,我在Interlocked.CompareExchange分配了很多对象,并将它们扔给GC,因为与( &&||相比,总是计算值(第二个参数) , which use short-circuit evaluation . ,其中使用short-circuit评估

Is lock the only alternative to atomically check for null and allocate a new object only if the target location is null ? 仅当目标位置为null lock才是原子检查null并分配新对象的唯一替代方法吗?

This test prints "I am created" three times and fails on the last assertion. 该测试将打印“我被创建”三遍,并且在最后一个断言时失败。

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
}

In my real code, I use TaskCompletionSource instead of the fake object. 在我的真实代码中,我使用TaskCompletionSource而不是假对象。 Does it matter? 有关系吗? Is there some pooling for TCS objects that makes allocation and collection irrelevant for them? 是否存在一些用于TCS对象的池,使它们的分配和收集不相关?

Before performing the Interlocked operation and the allocation see if the target location is not null already. 在执行Interlocked操作和分配之前,请查看目标位置是否还不为null。 If yes, there is no need to try and initialize it. 如果是,则无需尝试对其进行初始化。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM