可以在不相关的锁语句之后将读取指令移到锁之前吗? [英] Can a read instruction after an unrelated lock statement be moved before the lock?

查看:121
本文介绍了可以在不相关的锁语句之后将读取指令移到锁之前吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题是对线程中的注释的后续操作. >

假设我们有以下代码:

// (1)
lock (padlock)
{
    // (2)
}
var value = nonVolatileField; // (3)

此外,我们假设(2)中没有指令对nonVolatileField无效,反之亦然.

读取指令(3)是否可以重新排序以使其在锁语句(1)之前或内部(2)内结束?

据我所知,C#规范(第3.10节)和CLI规范(第I.12.6.5节)中没有任何内容禁止这种重新排序.

请注意,这不是与相同的问题一.在这里,我要特别询问已阅读的说明,因为据我了解,它们不被认为是副作用,而且保证程度较弱.

解决方案

相信 CLI规范部分保证了这一点,尽管目前尚不清楚.从I.12.6.5开始:

获取锁(System.Threading.Monitor.Enter或输入同步方法)应隐式执行易失性读取操作,然后释放锁 (System.Threading.Monitor.Exit或保留同步方法)应隐式执行易失性写操作.参见§I.12.6.7.

然后从I.12.6.7开始:

易失性读取具有获取语义",这意味着可以确保读取发生在CIL指令序列中的读取指令之后发生的对内存的任何引用之前.易失性写具有释放语义",这意味着该写保证在CIL指令序列中的写指令之前的任何内存引用之后发生.

因此,进入锁应防止(3)移至(1).我相信,从nonVolatileField读取仍然算作对内存的引用".但是,当锁退出时,仍可以在易失性写入之前执行读取,因此仍可以将其移至(2).

目前,C#/CLI内存模型还有很多不足之处.我希望可以对整个问题进行澄清(并可能加紧修改,以使某些理论上有效但实际上糟糕的"优化无效).

This question is a follow-up to comments in this thread.

Let's assume we have the following code:

// (1)
lock (padlock)
{
    // (2)
}
var value = nonVolatileField; // (3)

Furthermore, let's assume that no instruction in (2) has any effect on the nonVolatileField and vice versa.

Can the reading instruction (3) be reordered in such a way that in ends up before the lock statement (1) or inside it (2)?

As far as I can tell, nothing in the C# Specification (§3.10) and the CLI Specification (§I.12.6.5) prohibits such reordering.

Please note that this is not the same question as this one. Here I am asking specifically about read instructions, because as far as I understand, they are not considered side-effects and have weaker guarantees.

解决方案

I believe this is partially guaranteed by the CLI spec, although it's not as clear as it might be. From I.12.6.5:

Acquiring a lock (System.Threading.Monitor.Enter or entering a synchronized method) shall implicitly perform a volatile read operation, and releasing a lock (System.Threading.Monitor.Exit or leaving a synchronized method) shall implicitly perform a volatile write operation. See §I.12.6.7.

Then from I.12.6.7:

A volatile read has "acquire semantics" meaning that the read is guaranteed to occur prior to any references to memory that occur after the read instruction in the CIL instruction sequence. A volatile write has "release semantics" meaning that the write is guaranteed to happen after any memory references prior to the write instruction in the CIL instruction sequence.

So entering the lock should prevent (3) from moving to (1). Reading from nonVolatileField still counts as a "reference to memory", I believe. However, the read could still be performed before the volatile write when the lock exits, so it could still be moved to (2).

The C#/CLI memory model leaves a lot to be desired at the moment. I'm hoping that the whole thing can be clarified significantly (and probably tightened up, to make some "theoretically valid but practically awful" optimizations invalid).

这篇关于可以在不相关的锁语句之后将读取指令移到锁之前吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆