我正在从事一个项目,该项目涉及影响同一数据的多个流程和线程。我有一行代码可能会导致分段错误,因为可以从任何地方更新数据。 对于该特定行,如果它引起分段错误,我将以某种方式处理它而不是使程序崩溃。 就像我可以简单地更新内存位置(如果前一个引起分段错误)。 有什么可行的方法吗?
更新(我的情况的简短摘要):
我想非常快速地访问文件。 为此,我正在调用mmap(2)将该文件映射到所有访问该文件的进程中。我写入文件的数据采用特定数据结构的形式,并且占用大量内存。因此,如果要指出的是我映射的大小还不够,则需要增加文件大小,并使用新的大小再次mmap(2)该文件。为了增加大小,我调用ftruncate(2)。 ftruncate(2)可能会从任何进程中调用,因此最终可能会缩小文件。因此,我需要检查我正在访问的内存是否不会导致段错误。 我正在使用macOS。
答案 0 :(得分:2)
可以使此 起作用,但是通过将信号处理程序引入图片中,可以使进程间和线程间锁定问题变得更加复杂。我想建议一种替代方法:在mmapped文件的第一页中保留一个字段,以指示数据结构的预期大小。使用fcntl
文件锁来调解对此字段的访问。
当任何进程想要更新大小时,它需要写锁定,读取当前值,然后增加它,msync
s页(使用MS_ASYNC|MS_INVALIDATE
应该足够),然后 使用ftruncate
来扩大文件,然后扩大其对文件的映射,然后才释放写锁。如果在获得写锁定后发现文件已超出所需大小,则只需扩大映射并放下该锁定,不要调用ftruncate或更改字段。
这可确保协作进程永远不会使文件变小,并且每个进程映射的内存区域始终由分配的存储支持,因此您永远不会获得任何SIGBUS
。请注意,由于sparse files的神奇之处,磁盘上文件的大小只会在您实际写入新分配的空间时才会增加。
答案 1 :(得分:1)
是的,您可以使用捕获SIGSEGV或SIGBUS的信号处理程序来进行此操作,并调整mmap并返回。当信号处理程序返回时,它将恢复发生信号的位置,这意味着对于SIGSEGV或SIGBUS等同步信号,它将重新运行错误指令。
您可以在我的shared memory malloc实现中看到这一点-在malloc.c中搜索shm_segv
以查看信号处理程序;这很简单。我从未在MacOS上尝试过此代码,但是我认为它可以在OSX上运行,因为它可以在我尝试过的所有其他BSD派生的UNIX上运行。有一个问题,根据POSIX规范,mmap不是异步安全的,因此不能从信号处理程序中调用,但是在实际上支持实内存映射(而不是使用malloc + read进行仿真)的所有系统上,应该很好。