【问题标题】:Multiple threads and memory多线程和内存
【发布时间】:2009-11-03 10:28:28
【问题描述】:

我在 Visual C++ 文档中读到,多个线程从同一个对象中读取是安全的。

我的问题是:多核 X86-64 CPU 如何处理这个问题?

假设您有一个 1 MB 的内存块。不同的线程真的能够同时读取完全相同的数据,还是核心一次读取一个单词而一次只允许一个核心读取一个特定的单词?

【问题讨论】:

    标签: c++ multithreading cpu x86-64


    【解决方案1】:

    如果你的 1MB 块中真的没有写入,那么是的,每个内核都可以毫无问题地从自己的缓存行读取,因为没有写入被提交,因此不会出现缓存一致性问题。

    在多核架构中,基本上每个核心都有一个缓存和一个“缓存一致性协议”,它使某些没有最新信息的核心上的缓存无效。我认为大多数处理器都实现了MOESI protocol 以实现缓存一致性。

    缓存一致性是一个已被广泛讨论的复杂主题(我特别喜欢 Joe Duffy herehere 的一些文章)。尽管如此,讨论仍围绕代码可能的性能损失展开,虽然显然是无锁的,但由于缓存一致性协议启动以保持处理器缓存之间的一致性,可能会减慢速度,但是,只要没有写入,就根本没有保持一致性,因此不会损失性能。

    澄清一下,正如评论中所说,RAM 不能同时访问,因为 x86 和 x64 架构实现了一个在内核之间共享的单一总线,SMP 保证了访问主内存的公平性。尽管如此,每个核心缓存都隐藏了这种情况,这允许每个核心拥有自己的数据副本。对于 1MB 的数据,在核心更新其缓存时可能会引发一些争用,但这可以忽略不计。

    一些有用的链接:

    【讨论】:

    • 今天一般是正确答案。 RAM 本身不能支持多个并发访问,但这被缓存有效地隐藏了。但是如果多个核执行非缓存读取,这些请求仍然需要仲裁。
    【解决方案2】:

    不仅允许不同的内核从同一个内存块读取,还允许它们同时写入。如果它“安全”与否,那是一个完全不同的故事。您需要在您的代码中实现某种保护(通常使用信号量或它们的派生类完成),以防止多个内核以您不明确允许的方式争夺同一个内存块。

    关于内核一次读取的内存大小,通常是一个寄存器的值,32 位 cpu 上为 32 位,64 位 cpu 上为 64 位,依此类推。甚至流式传输也是逐个 dword 完成的(例如,查看 memcpy)。

    关于多核并发的实际情况,每个核使用单一总线来读取和写入内存,因此访问任何资源(内存、外部设备、浮点处理单元)都是一次一个请求,一个核一次。然而,核心内部的实际处理是完全并发的。 DMA 传输也不会阻塞总线,并发传输会排队并一次处理一个(我相信,这不是 100% 确定的)。

    编辑:只是为了澄清,与此处的其他回复不同,我仅在谈论无缓存方案。当然,如果内存被缓存,只读访问是完全并发的。

    【讨论】:

    • 对于现代处理器,任何内存访问实际上都有一个缓存线大小 = 64 字节。对缓存行的访问是原子的。线可以由核心共享以供阅读。
    猜你喜欢
    • 2010-12-09
    • 1970-01-01
    • 1970-01-01
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多