我的游戏有点像这样:
public static float Time;
float someValue = 123;
Interlocked.Exchange(ref Time, someValue);
Run Code Online (Sandbox Code Playgroud)
我想把时间变成Uint32; 但是,当我尝试使用UInt32而不是使用float值时,它会抗议类型必须是引用类型.Float不是引用类型,因此我知道在技术上可以使用非引用类型执行此操作.是否有任何实用的方法来使这项工作UInt32?
我一直在阅读类似问题的答案,但我仍然有点困惑......亚伯有一个很好的答案,但这是我不确定的部分:
...声明变量volatile会使每次访问都变得不稳定.不可能以任何其他方式强制执行此行为,因此不能用Interlocked替换volatile.在其他库,接口或硬件可以访问您的变量并随时更新它或需要最新版本的情况下,需要这样做.
是否Interlocked保证对所有线程的原子操作的可见性,或者我是否仍然必须volatile在值上使用关键字以保证对更改的可见性?
这是我的例子:
volatile int value = 100000; // <-- do I need the volitile keyword
// ....
public void AnotherThreadMethod()
{
while(Interlocked.Decrement(ref value)>0)
{
// do something
}
}
public void AThreadMethod()
{
while(value > 0)
{
// do something
}
}
Run Code Online (Sandbox Code Playgroud)
更新:
我是一个糟糕的运动,我改变了原来的例子,所以这里又是:
public class CountDownLatch
{
private volatile int m_remain; // <--- do I need the volatile keyword here?
private EventWaitHandle m_event;
public CountDownLatch(int count)
{
Reset(count);
}
public void …Run Code Online (Sandbox Code Playgroud) 我有一些必须是线程安全的代码,其行为类似于:
protected long m_RunningValue
protected long m_RunningCounter
protected object m_Lock = new object();
public long RunningValue { get { return Interlocked.Read(m_RunningValue); } }
public long RunningCounter { get { return Interlocked.Read(m_RunningCounter); } }
public void DoCalculation(int newValue, int newQuantity)
{
lock(m_Lock)
{
Interlocked.Add(ref m_RunningValueA, newValue);
Interlocked.Add(ref m_RunningCounter, newQuantity);
if(Interlocked.Read(ref newQuantity) == 0)
{
...m_RunningValue gets further modified here
}
}
}
计算必须锁定值和计数器,否则竞争条件可能影响if(...)块,但是在读出时它们根本不需要同步,即如果计数器和值在尝试之间发生变化读两个,这对我来说是100%的好.
读取时的互锁用于读取64位值的线程安全性.
混合联锁和锁这样安全吗?我在其他网页上看到混合它们是不安全的,但是如果这意味着混合它们是引入细微错误的好方法,或者如果在系统级别这会破坏所涉及的数据结构,我无法找到澄清.
所有这些互锁(64位.NET 4.0运行时)的成本是否完全违背了在属性get()方法周围保存ReaderWriterSlim锁的目的?
有没有办法实现一种类型的引用,其值可以与另一个原子交换?
在Java中,我们AtomicReference可以使用本地变量而不是其他变量进行交换AtomicReference.
你可以做:
AtomicReference r1 = new AtomicReference("hello");
AtomicReference r2 = new AtomicReference("world");
Run Code Online (Sandbox Code Playgroud)
并将它们与两个操作组合交换:
r1.set(r2.getAndSet(r1.get()));
Run Code Online (Sandbox Code Playgroud)
但是这使得它们之间处于不一致状态,两者都包含在内"hello".即使你可以原子地交换它们,你仍然无法原子地读取它们(作为一对).
我希望能做的是:
PairableAtomicReference r1 = new PairableAtomicReference("hello");
PairableAtomicReference r2 = new PairableAtomicReference("world");
AtomicRefPair rp = new AtomicRefPair(r1, r2);
Run Code Online (Sandbox Code Playgroud)
然后
Object[] oldVal, newVal;
do {
oldVal = rp.get();
newVal = new Object[] {oldVal[1], oldVal[0]};
} while (! rp.compareAndSet(oldVal, newVal));
Run Code Online (Sandbox Code Playgroud)
交换值,并在另一个线程中:
AtomicRefPair otherRP = new AtomicRefPair(r1, r2);
System.out.println(Arrays.toString(otherRP.get()));
Run Code Online (Sandbox Code Playgroud)
并确保输出将是[hello, world]或[world, hello].
笔记:
r1并且r2为此操作配对,但是另一个线程可能会独立配对,说r1 …我想使用WinAPI中的InterlockedExchange来使用无锁的线程同步.
目前我有一个这样的课.
struct DataExchange
{
volatile LONG m_value;
void SetValue(LONG newVal)
{
InterlockedExchange(&m_value, newVal);
}
LONG GetValue()
{
LONG workVal=0;
InterlockedExchange(&workVal, m_value);
return workVal;
}
};
Run Code Online (Sandbox Code Playgroud)
一个线程可以设置一个新值,另一个线程可以读取该值.
现在我想要做的是将LONG值更改为a struct.在WinAPI中有什么办法可以struct免费复制一个锁吗?
InterlockedCompareExchangeRelease()和之间有什么区别InterlockedCompareExchangeAcquire()?
当我尝试使用WIN32 API学习同步函数时,我发现有两个名称不同的函数,但似乎做同样的事情:
LONG __cdecl InterlockedCompareExchangeRelease(
__inout LONG volatile *Destination,
__in LONG Exchange,
__in LONG Comparand
);
Run Code Online (Sandbox Code Playgroud)
和
LONG __cdecl InterlockedCompareExchangeAcquire(
__inout LONG volatile *Destination,
__in LONG Exchange,
__in LONG Comparand
);
Run Code Online (Sandbox Code Playgroud)
我检查MSDN,它说这些功能是:
对指定的值执行原子比较和交换操作.该函数根据比较结果比较两个指定的32位值并与另一个32位值进行交换.
但对于InterlockedCompareExchangeAcquire(),
使用获取内存访问语义执行操作.
并且InterlockedCompareExchangeRelease(),
使用释放内存访问语义执行交换.
所以我很好奇这两个功能之间的区别.何时使用获取内存访问语义或释放内存访问语义?有什么例子吗?
谢谢!
我想用两种方法创建一个类:
void SetValue(T value) 存储一个值,但只允许存储单个值(否则会抛出异常).T GetValue() 检索值(如果还没有值,则抛出异常).我有以下愿望/约束:
GetValue()只有在最新值不存在时才抛出异常(null):null在调用SetValue()另一个线程后,它不应该基于陈旧值抛出异常.GetValue()如果值不为null,则表示不需要刷新值.我提出了几种实现这一目标的方法,但我不确定哪些是正确的,哪些是有效的,为什么它们(正确)和(有效),以及是否有更好的方法来实现我想要的东西.
Interlocked.CompareExchange写入场Interlocked.CompareExchange从外地来读Interlocked.CompareExchange(ref v, null, null)对字段执行操作后将导致下一次访问获得的值至少与Interlocked.CompareExchange看到的值相同.代码:
public class SetOnce1<T> where T : class
{
private T _value = null;
public T GetValue() {
if (_value == null) {
// Maybe we got a stale value (from the cache or compiler optimization).
// Read an …Run Code Online (Sandbox Code Playgroud) 我遇到了ConcurrentDictionary.NET 3.5 的实现(我很抱歉,我现在可以找到链接),它使用这种方法进行锁定:
var current = Thread.CurrentThread.ManagedThreadId;
while (Interlocked.CompareExchange(ref owner, current, 0) != current) { }
// PROCESS SOMETHING HERE
if (current != Interlocked.Exchange(ref owner, 0))
throw new UnauthorizedAccessException("Thread had access to cache even though it shouldn't have.");
Run Code Online (Sandbox Code Playgroud)
而不是传统的lock:
lock(lockObject)
{
// PROCESS SOMETHING HERE
}
Run Code Online (Sandbox Code Playgroud)
问题是:这样做有什么真正的理由吗?它更快还是有一些隐藏的好处?
PS:我知道有ConcurrentDictionary一些最新版本的.NET,但我不能用于遗留项目.
编辑:
在我的具体情况下,我正在做的只是Dictionary以一种线程安全的方式操作内部类.
例:
public bool RemoveItem(TKey key)
{
// open lock
var current = Thread.CurrentThread.ManagedThreadId;
while (Interlocked.CompareExchange(ref owner, current, 0) != current) { …Run Code Online (Sandbox Code Playgroud) Read(Int64).NET系统类System.Threading.Volatile和的方法有什么区别System.Threading.Interlocked?
具体而言,关于(a)原子性和(b)内存排序,它们各自的保证/行为是什么。
请注意,这是关于Volatile阶级,不是的volatile(小写)的关键字。
MS docs状态:
易读方法
读取字段的值。在需要它的系统上,插入一个内存屏障,以防止处理器按以下方式重新排序内存操作:如果在代码中此方法之后出现读取或写入,则处理器无法在此方法之前移动它。
...
退货
Int64读取的值。不管处理器数量或处理器缓存状态如何,此值都是计算机中任何处理器最新写入的值。
与
Interlocked.Read(Int64)方法
返回作为原子操作加载的64位值。
似乎特别令人困惑的是,这些Volatile文档没有谈论原子性,并且这些Interlocked文档没有谈论排序/内存障碍。
旁注:作为参考:我更熟悉C ++原子API,其中原子操作也总是指定内存排序语义。
Pavel有用地提供的问题链接(和可传递链接)很好地解释了挥发性记忆屏障和原子无撕裂阅读的区别/正交性,但它们并没有解释这两个概念如何应用于这两个类别。
Volatile.Read保证原子性?Interlocked.Read(或者,真的,任何的Interlocked功能)做出的内存为了任何保证?我正在寻找一个线程安全的计数器实现,使用Interlocked支持的任意值递增,并直接从Interlocked.CompareExchange文档中找到此示例(为简单起见略有改变):
private int totalValue = 0;
public int AddToTotal(int addend)
{
int initialValue, computedValue;
do
{
// How can we get away with not using a volatile read of totalValue here?
// Shouldn't we use CompareExchange(ref TotalValue, 0, 0)
// or Thread.VolatileRead
// or declare totalValue to be volatile?
initialValue = totalValue;
computedValue = initialValue + addend;
} while (initialValue != Interlocked.CompareExchange(
ref totalValue, computedValue, initialValue));
return computedValue;
}
public int Total
{
// This looks …Run Code Online (Sandbox Code Playgroud) interlocked ×10
c# ×7
volatile ×4
.net ×2
winapi ×2
atomic-swap ×1
c++ ×1
java ×1
lock-free ×1
windows ×1