首页 文章

易变量

提问于
浏览
18

我最近接受了一家软件公司的采访,他问我以下问题:

你能告诉我在变量前添加volatile的含义是什么吗?你能解释一下为什么这很重要吗?

我的大多数编程知识都来自C,但是工作岗位是针对C#的(我想我可能会根据具体问题的需要添加这些信息)

我回答说它只是让 compiler 知道变量可以跨进程或线程使用,并且它不应该对该变量使用优化;优化它可以恶化行为 . 简而言之,它是对编译器的警告 .

然而,根据采访者的说法,反过来说,volatile关键字警告 OS ,而不是编译器 .

我对此感到有些困惑,所以我做了一些研究,实际上找到了相互矛盾的答案!一些消息来源说这是针对编译器的,还有其他针对操作系统的 .

这是什么?它是否因语言而异?

2 回答

  • 3

    说实话,面试官提出的问题实际上有点模糊 .

    这实际上取决于他/她对"OS"的意思 . 他们是在谈论"upfront OS",纯粹的软件方面,或者他们可能误解了"OS"作为硬件 - 软件关系,即RTE和MMM(我在我自己的一些个人采访中看到了假设和比较) . 我认为值得注意的是,这两者截然不同!如果他/她在谈论前者,那么 NO volatile并不是OS . 如果他们正在谈论后者,那么是(这是一个宽松的是) . 此时,您处于语言之间差异的范畴 . 正如Cody Gray所提到的,C#是一种托管语言,因此后者对OS的定义确实是变量和采取的预防措施 .

    而且,无论在任何情况下还是OS的定义,编译器 does 都专门管理和处理volatile字段,而不管语言如何 . 否则,为什么首先要使用关键字?

    在我个人看来,这个值得的东西,我认为你的答案是正确的,尽管从评论来看,可能会变得复杂和忙乱 .

  • 23

    我回答说它只是让编译器知道变量可以跨进程或线程使用,并且它不应该对该变量使用优化;优化它可以恶化行为 . 简而言之,它是对编译器的警告 .

    这对C#来说是正确的方向,但是错过了一些重要的方面 .

    首先,完全删除“进程” . 变量不在C#中的进程之间共享 .

    其次,不要专注于优化 . 而是专注于允许的语义 . 编译器不需要生成最佳代码;需要编译器来生成符合规范的代码 . 重新排序不一定是出于性能原因而需要更快/更小/无论如何 . volatile声明对多线程程序的允许语义添加了额外的限制 .

    第三,不要将其视为对编译器的警告 . 它是编译器的一个指令:生成保证符合volatile变量规范的代码 . 编译器如何做到这一点取决于它 .

    这个问题的实际答案

    你能告诉我在变量前添加volatile的含义是什么吗?

    是:C#编译器和运行时环境具有很大的自由度,可以根据他们认为合适的任何原因重新排序变量读取和写入 . 它们仅限于那些在单个线程上保留程序含义的重新排序 . 所以“x = y; a = b;”可以将读取的b移到读取之前;这是合法的,因为结果没有变化 . (这不是重新排序的唯一限制,但在某种意义上它是最基本的限制 . )但是,重新排序允许在多个线程上注意到;另一个线程可能会观察到在y之前读取b . 这可能会导致问题 .

    C#编译器和运行时对可以如何相对于彼此重新排序易失性读取和写入有额外的限制,以及如何针对其他事件(例如线程启动和停止,锁定,抛出异常)对它们进行排序,等等 .

    有关读取,写入和其他效果的观察顺序的限制的详细列表,请参阅C#规范 .

    请特别注意即使使用volatile变量,也不需要从所有线程看到所有变量访问的一致总排序 . 具体而言,volatile "reads the latest value of the variable"只是假的概念;这句话表明存在"the latest value"这样的事情,这意味着总的一致排序 .

    如果这听起来令人困惑,那就是 . Don't write multithreaded programs that share data across threads. 如果必须,请使用最高级别的抽象 . 几乎没有人应该编写使用volatile的代码;使用TPL并让它管理你的线程 .

    现在让我们在C的背景下考虑你的答案 .

    关于C,问题是不适定的 . 在C#中,volatile是成员变量声明的修饰符;在C中,它是一种类型的一部分 . 所以说"before a variable"含糊不清;变量之前的位置? volatile int * xint * volatile x 之间存在差异 . (你能看到区别么?)

    但更重要的是:C规范并不保证volatile对线程有任何特定的行为 . 如果您的C编译器这样做,那么这是编译器供应商对该语言的扩展 . C中的易失性保证在内存映射IO,长跳转和信号方面具有某些行为,这就是全部;如果你依赖它来获得关于线程的某些行为,那么你正在编写不可移植的代码 .

    根据采访者的说法:反过来说,volatile关键字会警告操作系统,而不是编译器 .

    从开始到结束都是胡说八道 . 面试官不应该问他们不理解答案的问题 .

相关问题