我有一个带有静态成员的 C# 类,它从多个线程读取并在一个线程中写入。
据我所知Uint64读写并不是所有系统上的原子操作,所以我要手动保证线程安全。
我对如何做到这一点有一些想法。
使用原子包装类来实现,就像 C++ 中的 std::atomic 一样。在 C# 中是否有类似的实现?
对静态字段使用 volatile 修饰符。然而这是不允许的。为什么?
我最终做了以下事情:
private static object tick_time_lock; private static UInt64 _currentTickTime; public static UInt64 CurrentTickTime { get { return _currentTickTime; } set { lock (tick_time_lock) { _currentTickTime = value; } } }
这是使该字段线程安全的正确方法吗?
最佳答案
Is this the correct way of making this field thread-safe?
除非同步给定资源的所有 访问,否则监视器锁是没有意义的。锁定 set
访问器是毫无用处的,除非您还锁定了 get
访问器。正如您所说,UInt64
值的读写在所有平台上都不是原子的。如果在 set
访问器中仅写入第一个单词时,在 get
访问器中读取该字段会发生什么情况?你会得到一个撕裂的阅读。
Use the volatile modifier with static field. However this is not allowed. Why?
C# 语言设计者认为保证所有 volatile
字段访问都是原子的是有益的。作为权衡,您不能将任何 64 位字段声明为 volatile
。我不确定为什么做出这个决定。也许他们想避免向一些 volatile 读/写操作添加“隐藏”开销,而是要求开发人员依赖框架级设施,如 Thread.Volatile[Read/Write](ref long)
来处理64 位值。
Do it with and atomic wrapper class, like std::atomic in c++. Is there something similar implemented in C#?
是的。通过System.Threading.Interlocked
类暴露了框架级别的原子操作,包括Read
、Exchange
、CompareExchange
.
关于C# 线程安全的静态成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20205359/