从mmap-ed内存中进行有效读取,会产生负载下的SIGBUS。 为什么?

我有一个程序,将缓冲区复制到文件,mmap回来,然后检查其内容。 多个线程可以在同一个文件上工作。 偶尔,我在阅读时得到了SIGBUS,但是只在负载下。

映射是MAP_PRIVATE和MAP_POPULATE。 通过SIGBUS的崩溃发生在mmap成功后,我不明白,因为MAP_POPULATE被使用。

下面是一个完整的示例(在/ tmp / buf_ *下创build填充为零的文件),使用OpenMP创build更多的负载和并发写入:

// Program to check for unexpected SIGBUS // gcc -std=c99 -fopenmp -g -O3 -o mmap_manymany mmap_manymany.c #include <assert.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #define NBUFS 64 const char bufs[NBUFS][65536] = {{0}}; const char zeros[65536] = {0}; int main() { int count = 0; while ( 1 ) { void *mappings[ 1000 ] = {NULL}; #pragma omp parallel for for ( int i = 0; i < 1000; ++i ) { // Prepare filename int bufIdx = i % NBUFS; char path[ 128 ] = { 0 }; sprintf( path, "/tmp/buf_%0d", bufIdx ); // Write full buffer int outFd = -1; #pragma omp critical { remove( path ); outFd = open( path, O_EXCL | O_CREAT | O_WRONLY | O_TRUNC, 0644 ); } assert( outFd != -1 ); ssize_t size = write( outFd, bufs[bufIdx], 65536 ); assert( size == 65536 ); close( outFd ); // Map it to memory int inFd = open( path, O_RDONLY ); if ( inFd == -1 ) continue; // Deleted by other thread. Nevermind mappings[i] = mmap( NULL, 65536, PROT_READ, MAP_PRIVATE | MAP_POPULATE, inFd, 0 ); assert( mappings[i] != MAP_FAILED ); close( inFd ); // Read data immediately. Creates occasional SIGBUS but only under load. int v = memcmp( mappings[i], zeros, 65536 ); assert( v == 0 ); } // Clean up for ( int i = 0; i < 1000; ++i ) munmap( mappings[ i ], 65536 ); printf( "count: %d\n", ++count ); } } 

对我而言,没有任何断言,但程序在几秒钟后总是与SIGBUS崩溃。

用你当前的程序,可能会发生线程0创建/tmp/buf_0 ,写入并关闭它。 然后,线程1删除并创建/tmp/buf_0 ,但在线程1写入之前,线程0打开,映射和从/tmp/buf_0读取,因此尝试访问文件不包含64 kiB数据。 你得到一个SIGBUS

为了避免这个问题,通过使用omp_get_thread_num()而不是bufs来为每个线程创建唯一的文件/和bufIdx