linux - mmap 是原子的吗?

标签 linux multithreading concurrency mmap memory-mapping

mmap在它们的效果中调用原子?
也就是说,是否由 mmap 进行了映射更改以原子方式出现在访问受影响区域的其他线程中?
作为试金石,请考虑您执行 mmap 的情况。在一个全为零的文件中(来自线程 T1,此时是唯一的线程),然后启动从该区域读取的第二个线程 T2。然后,再次在 T1(原始线程)上执行第二个 mmap调用相同的区域,将映射替换为针对所有区域的文件的新映射。
阅读器线程是否有可能从某个页面读取一个 1(即,参见第二个 mmap 有效),然后随后从某个页面读取一个 0(即,参见第一个有效映射)?
您可以假设读取器线程上的读取被正确隔离,即上述效果不会仅仅由于 CPU/一致性级别的内存访问重新排序而发生。

最佳答案

Mmap(2)对于跨所有线程的映射是原子的;至少部分是因为 unmap(2)也是。分解一下,描述的场景类似于:

MapRegion(from, to, obj) {
     Lock(&CurProc->map)
     while MapIntersect(&CurProc->map, from, to, &range) {
            MapUnMap(&CurProc->map, range.from, range.to)
            MapObjectRemove(&CurProc->map, range.from, range.to)
     }
     MapInsert(&CurProcc->map, from, to, obj)
     UnLock(&CurProc->map)
}
在此之后,map_unmap必须确保在删除映射时,没有线程可以访问它们。请注意 Lock(&thisproc->map) .
MapUnMap(map, from, to) {
    foreach page in map.mmu[from .. to] {
         update page structure to invalidate mapping
    }
    foreach cpu in map.HasUsed {
         cause cpu to invoke tlb cache invalidation for (map, from, to)
    }
}
第一阶段是重写处理器特定页表以使区域无效。
第二阶段是强制每个曾经将此映射加载到其翻译缓存中的 cpu 使该缓存无效。该位高度依赖于架构。在较旧的 x86 上,重写 cr3通常就足够了,所以 HasUsed真的是CurrentlyUsing ;而较新的 amd64 可能能够缓存多个地址空间标识符,HasUsed 也是如此。 .在 ARM 上,本地 tlb 失效被广播到本地集群;所以HasUsed将引用集群 ID 而不是 CPU 的 ID。更多详情,请搜索 tlb shootdown ,正如俗称的那样。
一旦这两个阶段完成,就没有 thread可以访问这个地址范围。任何这样做的尝试都会导致故障,这将导致 faulting thread锁定它的映射结构,该结构已经被 mapping thread 锁定,所以它会一直等到映射完成。映射完成后,所有旧映射都已删除并由新映射替换,因此在此之后无法检索先前的映射。
如果另一个 thread在更新期间引用地址范围?它将继续处理陈旧数据或出现故障。在这方面,陈旧数据并不是不一致的,就好像它在 mapping thread 之前被引用了一样。已进入 mmap(2) .故障情况与 faulting thread 相同以上。
总之,对映射的更新是使用一系列确保地址空间一致 View 的事务来实现的。这些交易的成本是特定于架构的。实现这一点的代码可能非常复杂,因为它需要防范隐式操作,例如推测性获取,以及显式操作。

关于linux - mmap 是原子的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59845919/

相关文章:

c - C中多线程,求4个数组的平均值

haskell - Haskell 中的并发文件读/写?

java - 使用线程更新 JLabel

database - 并发 BEGIN–SELECT–INSERT 导致即时 SQLite3.7.6 "database locked"-error,覆盖忙超时?

linux - 将静态库链接到共享库时是否应该隐藏符号?

linux - ubuntu 中 lxc 上的 Oracle

Java 附加 API : UnsatisfiedLinkError

c - 如何检查是否在c中插入了内核模块?

c++ - std::shared_mutex 是否有利于作者而不是读者?

c - OpenMP : Parallel QuickSort