现代 CPU 中的多线程旧遗留应用程序 [关闭]

Posted

技术标签:

【中文标题】现代 CPU 中的多线程旧遗留应用程序 [关闭]【英文标题】:Multhithread old legacy applications in modern CPUs [closed] 【发布时间】:2017-12-23 04:36:29 【问题描述】:

我在解释为​​什么 volatile 关键字对于不同线程访问共享内存结构是必需的。

我的论点是假设 CPU 内部有两个内核和两个本地缓存。假设一个线程在一个内核中运行,而另一个线程在下一个内核中运行。然后,当第一个线程正在写入该内存,而第二个线程正在读取它时,第二个线程将看不到最新版本,因为它的本地缓存尚未更新。

但是我的朋友提出了一个论点,他认为在 'volatile' 关键字之前发生了什么,旧的多线程应用程序二进制文件在现代处理器中带来并运行,它们会失败吗?例如,一个旧的 32 位应用程序在 Windows 7 中带回并在多核 CPU 中运行?一个应用程序是在没有引入 CPU 内核的时代编写的,所以只有单个缓存?

是我朋友的说法是正确的。还是会失败? 'volatile' 关键字被引入 C/C++ 的时间范围是多久?

【问题讨论】:

投票结束的原因? When to use volatile with multi threading?的可能重复 很遗憾地通知您,您朋友的论点和您的论点都是not even wrong。甚至要开始解开嵌入在这两个立场中的所有错误假设,都需要一整本书。 This book might be a good place to start。 (注意:我实际上并没有读过那本书,这只是我在搜索引擎上抛出“c++并发”时出现的第一件事。) 【参考方案1】:

对于非常紧凑的循环,互斥锁可能不够用。我已经看到循环的代码使得编译器永远不会重新加载测试变量,无论是否使用互斥锁(是的,我现在知道在这样的循环中测试互斥锁无论如何都是糟糕的设计)。如果在该示例中存在互斥锁,则它将当前寄存器值转储到堆栈中,并在获取互斥锁后从该堆栈重新加载,而不是从原始变量的位置重新加载。在那种情况下,使用 volatile 会强制从正确的地址重新加载。如果没有互斥体,则循环足够紧密,不会出现任何寄存器溢出,因此如果没有 volatile,则根本不会重新加载。

【讨论】:

volatile 对我来说仍然模棱两可。它在某处告诉它只是关闭编译器优化,例如它总是强制变量从内存中读取,但不保证它会从向下的主内存中读取。有一些指令可以调用从主内存读取的内存,例如当 DMA 完成时,在这种情况下不涉及汇编我应该在 C 源代码级别使用什么关键字? @sandundhammika 为此,您可能正在寻找 C11 的原子类型。 如果我们不谈论 C11 怎么办?旧版本的 C++ 而不仅仅是 C 呢? @sandundhammika 在 C11 之前,一些编译器具有与 C11 原子类型等效的扩展,但没有通用的解决方案。【参考方案2】:

至于您在第一段中的想法。任何使用多个线程的程序都将使用互斥锁来一次只允许一个线程更改一块内存。

通常不需要 volatile 关键字。当您正在编译的程序无法控制的内容可能会干扰您在内存中的内容时,使用它。

如果您在计算机上运行旧应用程序,它只会使用一个处理器,因此您永远不会遇到任何问题。

使用 volatile 关键字时,它会告诉编译器要小心优化代码的方式。不优化代码的某些部分不会破坏任何东西。

【讨论】:

这个答案和问题一样,甚至都没有错,而且重复了对volatile 的常见误解。

以上是关于现代 CPU 中的多线程旧遗留应用程序 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

为啥 C# 中的多线程不能达到 100% CPU?

Redis 6 中的多线程是如何实现的!?

CAS在Java类中的应用

系统内的线程模型

Java中的多线程

Java中的多线程