Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何故意触摸内存页? 首先,在任何人抱怨之前,我意识到从理论上完美的C++代码的角度来看,内存模型是一个我不应该依赖的实现细节。然而,我更喜欢表现而不是纪律_C++_C_Multithreading_Memory Mapped Files - Fatal编程技术网

如何故意触摸内存页? 首先,在任何人抱怨之前,我意识到从理论上完美的C++代码的角度来看,内存模型是一个我不应该依赖的实现细节。然而,我更喜欢表现而不是纪律

如何故意触摸内存页? 首先,在任何人抱怨之前,我意识到从理论上完美的C++代码的角度来看,内存模型是一个我不应该依赖的实现细节。然而,我更喜欢表现而不是纪律,c++,c,multithreading,memory-mapped-files,C++,C,Multithreading,Memory Mapped Files,这里是一个场景:我有一个地址空间区域,我已经告诉操作系统使用我选择的文件返回该区域——也就是说,该文件是内存映射的。如果我对VMM通常如何工作的理解是正确的,那么操作系统在将页面加载到映射中时可能会非常懒惰,并且可能只有在实际接触页面时才会这样做 通常我可以忽略这个细节,但在这个特殊情况下,我将映射数据发送到工作线程池中。如果我只是天真地向工作线程传递一个指向此缓冲区的指针,那么当第一次触摸页面时,工作线程本身很有可能会遇到页面错误,这将导致工作线程阻塞,直到VMM实际加载页面为止 工作池的设计

这里是一个场景:我有一个地址空间区域,我已经告诉操作系统使用我选择的文件返回该区域——也就是说,该文件是内存映射的。如果我对VMM通常如何工作的理解是正确的,那么操作系统在将页面加载到映射中时可能会非常懒惰,并且可能只有在实际接触页面时才会这样做

通常我可以忽略这个细节,但在这个特殊情况下,我将映射数据发送到工作线程池中。如果我只是天真地向工作线程传递一个指向此缓冲区的指针,那么当第一次触摸页面时,工作线程本身很有可能会遇到页面错误,这将导致工作线程阻塞,直到VMM实际加载页面为止

工作池的设计是这样的,它的线程在I/O上阻塞是非常糟糕的,而在作业中发送的线程可以容忍被阻塞。因此,我想让我的发送者线程先接触映射的页面,这样页面错误就会阻止它

(我理解,不能保证先触摸页面会停止工作线程中随后出现的页面错误,但该程序在大多数情况下都是最佳的,并且总是正确的。)

在x86汇编语言中,这很简单:

; get the page's address in ebx
mov al, Byte Ptr [ebx]
遗憾的是,C或C++中不是那么简单。一个简单的实现很简单:

char *pPage = ...;
char Dummy = *pPage;
但是,这可能不起作用,因为任何有自尊心的优化器都会意识到代码什么也不做,只是省略了它

我们可以使用内联汇编,但这可能会严重削弱优化器。我们可以调用汇编语言函数来实现这一点,但这样我们就有了(无可否认的)不必要的函数调用开销

我们可以把
Dummy
变成一个外部可见的变量,这样可以工作,因为编译器不能假设赋值是无意义的。但是,这可能会导致CPU缓存线上的争用,从而严重降低多核系统的性能。(更不用说,我们浪费了缓存线和访问。)

我也想过这样做:

char volatile *pPage = ...;
char Dummy = *pPage;
我知道
volatile
关键字有两个保证:

  • 编译器不会对访问进行重新排序;及

  • 编译器不会假定连续读取之间的值相同

然而,这似乎不能保证编译器将读取该值,即使它不需要它


有什么想法吗?

volatile保证按照定义执行内存访问,因此一个简单的解决方案正是您建议的:

volatile char *prefetch_me = ...;
(void)*prefetch_me;
但是,如果您想以(可能)更有效的方式(并且您正在*ix系统上运行)触摸多个页面,请查看,特别是
MADV\u将需要
和/或
MADV\u顺序
。从手册页:

  • MADV_将需要
    -预计在不久的将来可以访问。(因此,最好先看几页。)
  • MADV_SEQUENTIAL
    -页面引用应按顺序排列。(因此,给定范围内的页面可以提前主动读取,并可能在访问后很快被释放。)

编译器实际上应该读取该值。任何对易失性对象的访问,无论是读还是写,都被认为是可观察的行为。为此烦恼是毫无意义的。在受保护模式的按需分页多任务操作系统上,线程可能会被阻塞一段时间的原因还有很多。被优先级更高的线程抢先,线程的机器代码被第二个换掉。@HansPassant我不担心抢先和我无法控制的代码交换,在这种情况下,除非用户运行其他应用程序,否则这通常不会太重要。我更担心的是,故意传递可能不存在的页面的工作线程,这很可能会使工作线程池暂停,故意每个核心只有一个线程,从而导致CPU利用率不足和延迟增加。作为一个交互式sim卡,在我的应用程序中不需要不必要的延迟。事实上,
volatile
有效。关于
madvise()
的有趣说明,也可能很好。请注意,我不希望在加载完成之前它一定会阻塞,因此它与触摸页面并不完全相同。我想知道是否有WinAPI等价于
madvise()