c# - 并发访问捕获的局部变量

标签 c# multithreading volatile

this 的上下文中和 this以前问过的问题,也在考虑this answer 我想知道在下面的 C# 代码中是否必须同步对本地捕获变量的访问。

// Let’s say we have two classes Person and Animal that are immutable. 
// Then there is some code that instantiates and uses instances of these classes:
public void SomeMethod() 
{ 
    Person person = null;
    Animal animal = null;

    Parallel.Invoke(() => person = CreatePerson(),  // some long running creation process
                    () => animal = CreateAnimal()); // some long running creation process

    // person and animal variables are used beyond this point in non-concurrent manner
}

上面的代码可能看起来好像我们正在访问局部变量,但是考虑到在幕后局部变量是 captured in closure并且访问这些捕获的变量发生在不同的线程中,我感觉缺少适当的内存屏障。

我的问题是:对人和动物变量的访问是否需要同步?如果是,以下是正确的做法还是我想多了?

Parallel.Invoke(() => Volatile.Write(ref person, CreatePerson()), 
                () => Volatile.Write(ref animal, CreateAnimal()));

更新 1

让我稍微复杂一点我的例子并解释我的思考过程。

// Let’s say we have two classes Person and Animal that are immutable. 
// Then there is some code that instantiates and uses instances of these classes:
public void SomeMethod() 
{ 
    Person person = CreatePersonLight(); // very fast creation process
    Animal animal = CreateAnimalLight(); // very fast creation process

    if (IsMonday())
    {
        Parallel.Invoke(() => person = CreatePersonHeavy(),  // some long running creation process
                        () => animal = CreateAnimalHeavy()); // some long running creation process
    }

    // person.Name and animal.Breed values are used beyond this point in non-concurrent manner
}

据我了解,这段代码涉及三个线程。第一个线程执行“SomeMethod”,第二个线程执行“CreatePersonH​​eavy”,第三个线程执行“CreateAnimalHeavy”。

我正在阅读 this article解释 c# 内存模型,它指出在 c# 中所有写入都是易变的,但读取不是。我想知道是否有可能将“CreatePersonLight”的结果“缓存”在第一个线程中,并且它不会看到任何第二个线程产生的结果。

此外,当我在 SomeMethod 的末尾访问一个人实例 (person.Name) 的属性时,由于 reordering 的原因,是否仍然不可能得到错误的结果? ?

更新 2

问题Making variables captured by a closure volatile肯定是相关的(这就是为什么它是我原来帖子中的第一个链接)但我不认为是相同的/重复的。此外,它还表明:

...it would appear that there is no way to force volatile semantics onto captured local variables...

我不确定这是真的。也就是说,它仍然没有直接回答我的问题,在此处介绍的代码中,对捕获变量的访问是否必须同步。

最佳答案

经过更多的阅读和研究,我想我可以回答我自己的问题。

确实是我想多了。

由于 C# 规范的 3.10 执行顺序部分,原始代码和 Update 1 的代码都不需要同步:

Execution of a C# program proceeds such that the side effects of each executing thread are preserved at critical execution points. A side effect is defined as a read or write of a volatile field, a write to a non-volatile variable, a write to an external resource, and the throwing of an exception. The critical execution points at which the order of these side effects must be preserved are references to volatile fields (§10.5.3), lock statements (§8.12), and thread creation and termination.

我对规范的理解是,在 Parallel.Invoke 完成后,我保证在“person”和“animal”中看到正确的值

关于c# - 并发访问捕获的局部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35976323/

相关文章:

c# - 由 ThreadPool 中的线程填充的 ObservableCollection

c - 隐式声明所有变量 volatile

c# - 注销必须在 asp.net 中单击两次

C#/.NET - 查看系统事件列表,即。已显示的窗口、已单击的按钮等

java - 发送大量 POST 请求

c# - 是否有与 Java 的 CountDownLatch 等效的 C#?

java - 在两个同步块(synchronized block)和多个 volatile 读/写的情况下重新排序

Java 同步来自 JavaScript 的异步调用

c# - "Unable to translate Unicode character"保存到txt文件时出错

c# - Windsor WCF 集成工具异步