编程语言
首页 > 编程语言> > c#-用这种方式实现原子双精度/长整型/日期时间/可空值有什么问题吗?

c#-用这种方式实现原子双精度/长整型/日期时间/可空值有什么问题吗?

作者:互联网

您不能将double,long,DateTime,任何可为空或任何其他结构声明为volatile(如果可以,因为写不是原子的,这是行不通的),但是在我的特殊情况下,我需要一个由原子写的volatlie约会时间?.

我写了这个简单的类来确保写是原子的.如果您按以下方式进行复制,它将始终具有写入之前的值或写入之后的值,永远不会有任何不完整的值.

/// <summary>
/// A T? where writes are atomic. Implemented as a class (which always has atomic read/writes) containing a readonly value.
/// </summary>
public class AtomicNullable<T> where T: struct {
    public readonly T Value;

    public AtomicNullable(T value) {
        this.Value = value;
    }

    public static implicit operator AtomicNullable<T>(T value) {
        return new AtomicNullable<T>(value);
    }
}

用法:

private volatile AtomicNullable<DateTime> expiryTime = null;

private bool IsExpired() {
    // Copy of expiry makes sure it doesn't get set from another thread in the middle of evaluating the boolean expression.
    AtomicNullable<DateTime> expiry = this.expiryTime;
    return expiry == null
        || expiry.Value < DateTime.UtcNow;
}


private void Calculate() {
    if (IsExpired()) {
        lock (locker) {
            if (IsExpired()) {
                // do calculation...
                expiryTime = DateTime.UtcNow + MaximumCachedObjectAge;
            }
        }
    }
}

解决方法:

看起来您已经重新发明了拳击(除非具有更大的类型安全性).

private volatile object expiryTime = null;

private bool IsExpired()
{
    object expiry = this.expiryTime;
    return expiry == null
        || (DateTime)expiry < DateTime.UtcNow;
}

但是,类型安全性很好.

这些是我将要更改的事情:

Calculate()应该是CalculateIfExpired(),并且应该调用Calculate()来完成实际工作.

目前,Calculate正在设置expiryTime字段.当不知道如何读取expiryTime时,为什么应该知道如何设置expiryTime?相反,IsExpired()应该在工具架上旁边有一个漂亮的小SetExpired().并且代码应该假装expiryTime仅在这两个方法的作用域内(或创建另一个类,因此不必假装).

现在终于可以回答您的问题了:-)

我同意@Eric Lippert的观点,即除非证明它不够好,否则基本锁定比双重检查锁定要好.我认为,只要您永不忘记将控制变量标记为volatile,就可以再次检查锁定.我见过的这种方法的所有问题都假定变量不是易失的.

标签:thread-safety,atomic,c
来源: https://codeday.me/bug/20191208/2092456.html