简体   繁体   English

在C#中使用Volatile.Write()而不是volatile

[英]Usage of Volatile.Write() instead of volatile in C#

Assume the following code (note that this is only an example code): 假设以下代码(请注意,这只是一个示例代码):

public async void UnsafeMethod()
{
  int unsafeValue = 0;

  Task.Run(() => unsafeValue = 42 ); // set unsafeValue to some value
  await Task.Delay(10);              // wait for some time

  Assert.AreEqual(42, unsafeValue);  // check if unsafeValue has the new value
}

(Assume here that the CPU is idle and executes the task immediately.) (这里假设CPU处于空闲状态并立即执行任务。)

Since the task will be executed on a new thread, the new value of unsaveValue might not be visible to other threads due to possible caching issues. 由于任务将在新线程上执行, unsaveValue可能由于可能的缓存问题, unsaveValue的新值可能对其他线程不可见。 If i want to make the change visible, i would have to use volatile and make the local variable a field: 如果我想使更改可见,我将不得不使用volatile并使局部变量成为一个字段:

private volatile int safeValue = 0;

public async void SafeMethod()
{
  Task.Run(() => safeValue = 42 ); // set safeValue to some value
  await Task.Delay(10);            // wait for some time

  Assert.AreEqual(42, safeValue);  // check if safeValue has the new value
}

(Assume again that the task is executed immediately.) (再次假设任务立即执行。)

My question now is, if the following will do the same while keeping the local variable (i know, the compiler makes it a field anyways...): 我现在的问题是,如果以下内容在保持局部变量的同时也会这样做(我知道,编译器会使它成为一个字段...):

public async void AnotherMethod()
{
  int safeValue = 0;

  Task.Run(() => Volatile.Write(ref safeValue, 42); // set safeValue to some value
  await Task.Delay(10);                             // wait for some time

  Assert.AreEqual(42, safeValue);                   // check if safeValue has the new value
}

(Task gets executed immediately.) (任务立即执行。)

The documentation is not entirely clear to me. 文档对我来说并不完全清楚。 https://msdn.microsoft.com/en-us/library/system.threading.volatile(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/system.threading.volatile(v=vs.110).aspx

It states: 它指出:

On a multiprocessor system, a volatile write operation ensures that a value written to a memory location is immediately visible to all processors. 在多处理器系统上,易失性写入操作可确保写入内存位置的值立即对所有处理器可见。

which is what I want. 这就是我想要的。 However, it also states: 但是,它还指出:

Writes the specified value to the specified field. 将指定的值写入指定的字段。 On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. 在需要它的系统上,插入一个内存屏障,阻止处理器重新排序内存操作,如下所示:如果在代码中此方法之前出现读取或写入,则处理器无法在此方法之后移动它。

at the method description, which I am not sure if this is what I want. 在方法描述中,我不确定这是否是我想要的。

Again my question: Will the last code snipped do what i want it to do (make the write immediately visible to other threads)? 我的问题再一次:最后一个代码是否会剪切我想要它做的事情(使写入立即对其他线程可见)?

As Matteo Umili and Matthew Watson mentioned in the comments you have to use Volatile.Read when you read a non-volatile field. 正如Matteo UmiliMatthew Watson在评论中提到的那样,当你阅读非易失性字段时,你必须使用Volatile.Read That's because synchronization is always a 2 player game. 那是因为同步总是2人游戏。

In this case Volatile.Write inserts store-release barrier after the write and Volatile.Read sets load-acquire barrier before the read. 在这种情况下, Volatile.Write在写入后插入存储释放障碍,而Volatile.Read在读取之前设置load-acquire障碍。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM