在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”的第一个线程,执行“CreatePersonHeavy”的第二个线程,以及执行“CreateAnimalHeavy”的第三个线程。
我正在阅读解释c#内存模型的this article,并指出在c#中所有写操作都是易失性的,但读取不是。我想知道是否有可能“CreatePersonLight”的结果在第一个线程中被“缓存”,并且它不会看到任何第二个线程产生的。
此外,当在SomeMethod的末尾我访问一个人物实例(person.Name)的属性时,由于reordering而无法得到错误的结果吗?
更新2
问题Making variables captured by a closure volatile肯定是相关的(这就是为什么它是我原帖中的第一个链接),但我认为不一样/重复。除此之外,它暗示:
......似乎没有办法强制将易失性语义强加到捕获的局部变量上......
我不确定是不是真的。那说它仍然没有直接回答我的问题是否在这里提供的代码访问捕获的变量必须同步或不同步。
答案 0 :(得分:0)
经过一些阅读和研究后,我想我可以回答我自己的问题。
我确实在思考它。
在原始代码和Update 1的代码中,由于C#规范的 3.10执行顺序部分,不需要同步:
执行C#程序,以便在关键执行点保留每个执行线程的副作用。副作用定义为易失性字段的读取或写入,写入非易失性变量,对外部资源的写入以及抛出异常。 关键执行点,必须保留这些副作用的顺序 引用易失性字段(第10.5.3节),锁定语句(第8.12节)和< strong>线程创建和终止。
我对规范的理解是,在Parallel.Invoke完成后,我保证在“人物”和“动物”中看到正确的值