Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# .Net比较交换重新排序_C#_.net_Multithreading_Memory Fences_Test And Set - Fatal编程技术网

C# .Net比较交换重新排序

C# .Net比较交换重新排序,c#,.net,multithreading,memory-fences,test-and-set,C#,.net,Multithreading,Memory Fences,Test And Set,编译器或处理器是否可以对以下指令重新排序,以便另一个线程看到a==0和b==1 假设inta=0,b=0某处 System.Threading.Interlocked.CompareExchange<int>(ref a, 1, 0); System.Threading.Interlocked.CompareExchange<int>(ref b, 1, 0); System.Threading.interlocated.compareeexchange(参考a,1,0

编译器或处理器是否可以对以下指令重新排序,以便另一个线程看到
a==0
b==1

假设
inta=0,b=0某处

System.Threading.Interlocked.CompareExchange<int>(ref a, 1, 0);
System.Threading.Interlocked.CompareExchange<int>(ref b, 1, 0);
System.Threading.interlocated.compareeexchange(参考a,1,0);
系统。线程。联锁。比较交换(参考b,1,0);

当然可以。组成
CompareExchange
操作的单个操作不能明显地重新排序,但对
CompareExchange
的两个调用可以从另一个线程的角度重新排序,只要执行此代码的线程不能观察到这样的行为


CompareExchange
的同步工具可防止影响与该操作相关的内存位置的操作之间的可观察到的重新排序,而不是一般的任何操作,代码中也没有任何东西可以防止编译器或JITter对这两个
CompareExchange
调用进行完全重新排序(从另一个线程的角度)。

否。使用
互锁
将表示内存已满。“也就是说,任何变量在调用
Interlocked
方法之前写入,在
Interlocked
方法之前执行,任何变量在调用之后读取。”[1]他们使用易失性读/写方法来防止
b=1
a=1
之前执行


[1] :Jeffrey Richter:“CLR通过C#-第三版”第五部分线程,第803页

你读的理论太多了。是的,如果另一个线程这样做,它在实践中可能会发生

Console.WriteLine("a: {0}, b: {1}", a, b);
因为用于格式化字符串的String.Format的签名为

   String Format(string fmt, params object[] args)
   {
       ....
   }
由于装箱,您的整数将被复制。唯一需要为true的条件是,线程时间片在复制处于单元化状态的时结束。稍后,当线程恢复工作时,两个变量都设置为一,但控制台输出将为

a: 0, b: 1
如果您在未意识到的情况下使用值的副本,则会立即看到其他值。这就是为什么您通常让其他人编写正确的无锁代码的原因。如果您尝试使用Console.WriteLine调试无锁代码,我祝您好运


虽然a和b是按顺序设置的(我不认为JIT编译器会重新排列您的联锁调用),但您不能保证其他线程只看到两个0或两个1。您可以尝试读取第一个b并检查它是否具有值1,然后您可以推断a的值,但在这种情况下,您甚至不需要a的值。至少对于x86内存模型来说应该是这样。这种假设可能会被ARM等较弱的内存模型打破。

不,它不能@usr请。。。(一份参考资料就足够了。)这是个问题。NET内存模型不会对互锁的AFAIK进行声明。联锁始终被理解为提供这种行为。但是文档很弱(例如)。我很确定我的说法是正确的,但很难找到引用。这个问题可能是语言律师标签的一个很好的候选者,我建议添加它。我认为,如果没有记录,所有涉及潜在写入的
互锁
操作都有发布语义,而那些具有潜在读写能力的人则获得了语义。第二个
CompareExchange()
调用上的释放屏障将阻止第一个调用被重新排序超过它。这些易失性方法防止影响这些操作中使用的内存位置的操作被重新排序,它们不会影响影响应用程序其余部分的所有其他操作。@Servy我不认为这可能是真的,或者
lock
的行为会崩溃。
锁的正确运行取决于防止读取和写入在其子块外重新排序的屏障,而这些读取和写入通常不在锁目标的同一位置。@MikeStrobel假设两个工具使用相同的同步机制<代码>锁
有不同的、更严格的同步机制,它用来强制执行其行为。@请注意,clr内存模型不是我的强项(上次我检查时,它的文档也严重不足)-JMM是。但据我所知,可以保证联锁指令包含一个完整的内存屏障(尽管获取/释放对我们来说已经足够了)其中“是”保证禁止重新排序。@Servy我读到的关于获取/释放语义的每个定义都将其描述为禁止对任何超出界限的读/写进行重新排序。我怀疑这是一个理论与实践将发生分歧的时代,因为我不知道有哪一个现代建筑不符合这些定义。如果有人能提供一个权威性的反例,我当然想知道我是否错了。这是一个不应该被忽视的观点。最初的问题是“编译器或处理器能否重新排序以下指令…”,我们都同意它不会重新排序指令。是的,我们都同意。我想强调一点,没有锁的无锁代码将导致使用锁时从未见过的副作用。很高兴知道它背后的理论,但在现实中,约30%的速度增加是很少值得的努力。大多数情况下,通过重新设计数据结构可以获得更多。