Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.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#中进行多线程处理时,为什么要使bool不稳定? 我理解C++中的代码>但在C#中,它似乎有不同的含义,与多线程更相关。我认为bool操作是原子的,我认为如果操作是原子的,就不会有线程问题。我错过了什么_C#_Multithreading - Fatal编程技术网

在C#中进行多线程处理时,为什么要使bool不稳定? 我理解C++中的代码>但在C#中,它似乎有不同的含义,与多线程更相关。我认为bool操作是原子的,我认为如果操作是原子的,就不会有线程问题。我错过了什么

在C#中进行多线程处理时,为什么要使bool不稳定? 我理解C++中的代码>但在C#中,它似乎有不同的含义,与多线程更相关。我认为bool操作是原子的,我认为如果操作是原子的,就不会有线程问题。我错过了什么,c#,multithreading,C#,Multithreading,我以为布尔运算是原子的 它们确实是原子的 我认为如果操作是原子的,就不会有线程问题 这就是你有一个不完整的图片。假设有两个线程运行在不同的内核上,每个内核都有自己的缓存层。线程1的缓存中有foo,线程2更新foo的值。线程1不会看到更改,除非foo标记为volatile,获取锁,使用类,或显式调用Thread.MemoryBarrier(),这将导致值在缓存中无效。因此: 使用volatile修饰符可以确保一个线程检索另一个线程写入的最新值 Eric Lippert有一篇关于波动性的文章,他解释

我以为布尔运算是原子的

它们确实是原子的

我认为如果操作是原子的,就不会有线程问题

这就是你有一个不完整的图片。假设有两个线程运行在不同的内核上,每个内核都有自己的缓存层。线程1的缓存中有
foo
,线程2更新
foo
的值。线程1不会看到更改,除非
foo
标记为
volatile
,获取
,使用类,或显式调用
Thread.MemoryBarrier()
,这将导致值在缓存中无效。因此:

使用volatile修饰符可以确保一个线程检索另一个线程写入的最新值

Eric Lippert有一篇关于波动性的文章,他解释道:

volatile读取的真正语义 写作比我在这里概述的要复杂得多;在里面 事实上,它们并不能保证每个处理器都停止它所做的事情 正在执行和更新主存的缓存。相反,它们提供 关于如何在读和写之前和之后访问内存的较弱保证 可以观察到写操作彼此之间的顺序。

编辑:


根据@xanatos的评论,这并不意味着
volatile
保证立即读取,它保证读取最新的值。

C#中的
volatile
关键字都是关于读/写重新排序的,所以这是一个相当深奥的东西

(我认为是线程的“圣经”之一)写道:

volatile关键字指示编译器在每次读取该字段时生成一个获取围栏,在每次写入该字段时生成一个释放围栏。获取围栏防止在围栏之前移动其他读/写操作;释放围栏可防止其他读/写操作在围栏之后移动。这些“半围栏”比全围栏快,因为它们为运行时和硬件提供了更多的优化空间

这是很难理解的:——)

现在。。。这并不意味着什么:

  • 这并不意味着现在将读取值/现在将写入值
这仅仅意味着,如果您从一个易失性变量中读取了一些内容,那么在此“特殊”读取之前读取/写入的所有其他内容都不会在该“特殊”读取之后移动。所以它制造了一个障碍。因此,自相矛盾的是,通过读取volatile变量,可以保证在读取点对任何其他变量(volatile或not)所做的所有写入操作都将完成

易失性写入可能更为重要,部分由Intel CPU保证,而第一版Java无法保证:无写入重新排序。问题是:

object myrefthatissharedwithotherthreads = new MyClass(5);
在哪里

现在。。。这个表达可以想象为:

var temp = new MyClass();
temp.Value = 5;
myrefthatissharedwithotherthreads = temp;
其中
temp
是由编译器生成的、您看不到的内容

如果写入操作可以重新排序,则可以:

var temp = new MyClass();
myrefthatissharedwithotherthreads = temp;
temp.Value = 5;

另一个线程可能会看到部分初始化的
MyClass
,因为在类
MyClass
完成初始化之前,与其他线程共享的
myref的值是可读的。

volatile
防止围绕变量访问的指令重新排序。这相当复杂。实际上,在C++和C语言之间的语义的语义差异方面有很好的描述。
volatile
write不能保证立即写入。@xanatos我不是说它保证立即写入。声明它保证了对更新值的读取。您在写入
volatile
:-)两次写入,两次出错:-):-)@xanatos a crap:X时遇到问题。修复了此问题。
volatile
不仅阻止了围栏,还阻止了诸如持续传播、死代码消除或寄存器提升等优化。它比简单的栅栏更具限制性。@Cicada你有没有关于C#的参考资料?
var temp = new MyClass();
myrefthatissharedwithotherthreads = temp;
temp.Value = 5;