File io 跨平台和跨进程在文件上写入原子int

File io 跨平台和跨进程在文件上写入原子int,file-io,locking,mutex,blocking,spinlock,File Io,Locking,Mutex,Blocking,Spinlock,我正在编写一个应用程序,它必须能够处理对它的许多并发访问,无论是通过线程还是通过进程。因此,不应对此应用互斥锁或锁 为了尽量减少锁的使用,我将文件设计为“仅追加”,因此所有数据首先追加到磁盘,然后指向已更新信息的地址被更改为引用新的地址。所以我只需要实现一个小的锁系统来改变这个int,使它指向新的地址。 最好的方法是什么 我在考虑在地址前放一个标志,当它被设置时,读者会使用旋转锁直到它被释放。但我担心它根本不是原子的,是吗? e、 g 读卡器读取该标志,该标志未设置 同时,写入程序写入标志并更

我正在编写一个应用程序,它必须能够处理对它的许多并发访问,无论是通过线程还是通过进程。因此,不应对此应用互斥锁或锁

为了尽量减少锁的使用,我将文件设计为“仅追加”,因此所有数据首先追加到磁盘,然后指向已更新信息的地址被更改为引用新的地址。所以我只需要实现一个小的锁系统来改变这个int,使它指向新的地址。 最好的方法是什么

我在考虑在地址前放一个标志,当它被设置时,读者会使用旋转锁直到它被释放。但我担心它根本不是原子的,是吗? e、 g

  • 读卡器读取该标志,该标志未设置
  • 同时,写入程序写入标志并更改int的值
  • 读卡器可能读取不一致的值
我正在寻找锁定技术,但我发现的只是线程锁定技术,或者锁定整个文件,而不是字段。不可能这样做吗?仅附加数据库如何处理此问题

编辑: 我在看append only db(couchDB)是如何做到这一点的,他们似乎只使用线程来序列化对文件的写入。这是否意味着如果不使用文件系统锁锁定整个文件,就不可能使它们像sqlite一样可嵌入

谢谢!
Cauê

当我需要这样做时,通常我会编写一个进程,它接受来自其他进程的多个连接以获取数据。此日志记录过程可以在写入所有数据的位置维护一个文件指针,而不会在同一位置发生多次写入的风险


日志进程中的每个线程只侦听新输入并将其提交到队列,而不阻塞生成数据的进程。在生成要记录的数据的线程中尝试这样做(写入磁盘)最终会使您处于一种必须进行锁定操作的境地,并遭受它们所要求的任何性能损失。

请注意文件系统的附加语义-它可能不提供原子附加操作

一个选项是将文件映射为共享的内存(
mmap
),然后在指针上执行原子内存操作,如比较和交换。您的成功将取决于您的操作系统是否有这样的操作(Linux、OSX-do)


一种正确(尽管我不确定它是否快速)的方法是使用
重命名
——它是大多数文件系统上的一种原子文件操作。将最新数据保存在官方文件位置。要更新数据,请将新数据写入临时文件,然后将该临时文件重命名为正式位置。

谢谢您的回答!我不知道mmap也可以写入文件,我以为它只能从中读取。如果windows等效文件(MapViewOfFile)也能按预期工作,那么它很可能是一个选项。但我不知道是否有跨处理器的方式来使用比较和交换功能。关于附加语义,我认为在这种情况下,普通的文件系统文件锁可以很好地工作,不是吗?改名是不可能的。这是我正在研究的一个数据库原型,它应该能够处理非常大的文件和不断的写入。将页面映射到数组,然后在需要写入时使用比较和交换,这是一个好的工作流吗。mmap页面会变慢吗?mmap保证是原子的吗?我还没有找到任何说它是的参考资料,但也没有一个说它不是!对我来说,这听起来是个不错的工作流程。mmap的页面并不慢(至少在linux上是如此),事实上,它们应该比使用读/写更快,因为它们避免了任何复制(虚拟内存直接映射到文件系统缓存中的页面)。在Windows上必须是相同的,该方案才能工作——两个进程中的两个mmap’d区域需要映射到相同的物理内存,以便进行比较和交换才能工作。mmap调用是否原子化与您的情况无关。您需要的唯一原子性是在已经mmap的内存上进行比较和交换的操作。但是我在mmap上使用比较和交换不是很可能,但是从内存实际更新到实际硬盘所需的时间可能会导致一些同步问题吗?它也应该可以跨进程工作,只要您共享mmap,同一物理内存页将支持所有mmap'd区域。感谢您的回答!但是,如果一个读卡器碰巧正在读写器进程正在写入的数据——即使它只是一个int指针,它仍然可以在不一致的状态下捕获它,不是吗?另外,我希望避免使用这种进程通信,因为我希望使这个数据库原型像sqlite一样可嵌入。通过制作两个锁,并以与编写相反的顺序读取它们,是否可以实现一个丑陋的解决方案?