【问题标题】:Force two threads to access a global variable directly in memory?强制两个线程直接访问内存中的全局变量?
【发布时间】:2014-11-22 01:19:31
【问题描述】:

我知道 C++ 中的 volatile 与 Java 中的含义不同,所以如果我正在为 Windows 编写 C++ 应用程序,如何在两个线程之间共享一个变量并且不允许让每个线程缓存自己的变量副本? 使用临界区能解决这个问题还是只允许原子性?

【问题讨论】:

    标签: c++ multithreading winapi


    【解决方案1】:

    实际上,在 Visual Studio 中,volatile 的含义与 Java(或 C#)中的含义几乎相同。或者至少,它曾经并且默认情况下仍然如此;详情请见Microsoft's documentation

    也就是说,在标准 C++ 中,volatile 确实几乎没有任何意义。此外,用标准术语来说,线程不会“缓存”任何东西,而且您的问题格式不正确。相关的概念是atomicityordering,后者的标准术语是“happens-before”关系。设计、实现和推理多线程算法所需的一切都包含在这些概念中; “缓存”的概念与它无关。

    标准 C++11 提供了许多机制来强制执行原子性和排序。如果您提出有关实现特定算法的特定问题,您将得到更好的答案。

    [更新,澄清]

    请注意,我并不是说您使用了错误的术语;我是说你使用了错误的概念

    标准没有用不同的词谈论“缓存变量”......它根本没有谈论缓存变量。那是因为这个概念对于推理线程来说既非必要也不充分。你可以对缓存一无所知,但仍然无法分析并发算法,你对缓存一无所知,却能够完美地分析它们。

    同样,“直接访问变量”不仅仅是错误的说法;这个概念在(标准)C++ 中是没有意义的。当每个线程以不同的速度进行并以不同的顺序观察状态变化时,“立即执行”的概念毫无意义。在标准 C++ 中,根本没有“直接访问”或“立即访问”;只有发生在之前。

    这不是学术观点。错误的并发思维模型几乎肯定会导致思维模糊和草率、错误的代码。

    您的问题确实没有像措辞那样的答案。正确的答案可能是使用std::atomic 或使用std::mutex 或使用std::atomic_thread_fence,具体取决于您实际尝试执行的操作。我建议你问一个清楚说明那是什么的问题。

    【讨论】:

    • 我不知道正确的术语是什么,但我所说的“缓存”是指每个线程读取和写入自己的全局变量副本。反正如果 WinAPI 没有提供任何机制来解决这个问题,我想在 VC++ 中使用 volatile 就足够了!
    • @mahmoud_t1:这取决于你在做什么。您可能仍然需要临界区或其他一些同步机制,除非您的程序只在单核系统上运行。如果您使用关键部分,则不需要volatile
    • 我所做的只是让两个线程运行,一个线程写入全局变量,另一个线程读取全局变量。 “如果你使用临界区,你就不需要 volatile”,这是否意味着如果我将读/写代码放在临界区中,我可以依赖全局变量将被直接访问?
    • 传统上,编译器确实被允许做一些事情,比如将非易失性变量临时存储在寄存器中,或者假设它不会从另一个线程自发更改。称其为“缓存”并没有太大的错误。但是,临界区是通过调用 Win32 API 函数来实现的,并且传统的编译器必须假设这样的调用可能会读取和/或更改变量的值。实际上,这可以防止问题发生。
    • 然而,这不是最佳实践,至少有两个原因:(1) 原则上,现代编译器实际上可能认为它知道 EnterCriticalSection() 不会读取或修改变量有问题; (2) 它不遵循编译器设计的现代概念模型。
    猜你喜欢
    • 1970-01-01
    • 2020-11-09
    • 1970-01-01
    • 1970-01-01
    • 2015-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多