在不同的平台上有不同的东西吗?

时间:2009-04-20 00:19:44

标签: c++ file file-io cross-platform

我在C ++中编写一个并发的持久性消息队列,它需要对文件进行并发读访问,而不使用内存映射io。简短的故事是,几个线程需要从文件的不同偏移量中读取。

最初我有一个具有典型读/写方法的文件对象,并且线程会获取一个互斥锁来调用这些方法。但是,碰巧我没有在某处正确获取互斥锁,导致一个线程在读/写期间移动文件偏移量,另一个线程将开始读/写文件的错误部分。

因此,偏执的解决方案是每个线程有一个打开的文件句柄。现在我对同一个文件有很多文件句柄,我假设它不是很好。

我想使用类似pread的东西,它允许将当前偏移传递给读/写函数。

但是,该功能仅适用于linux,我需要在windows,aix,solaris和hpux上有相应的实现吗?

3 个答案:

答案 0 :(得分:6)

在Windows上,ReadFile()功能可以执行此操作,请参阅lpOverlapped参数和this info on async IO

答案 1 :(得分:4)

使用NIO,java.nio.channels.FileChannelread(ByteBuffer dst, long position)方法,内部使用pread

等等,你的问题是关于C ++,而不是Java。好吧,我只是看了JDK源代码,看看它是如何为Windows做的,但不幸的是在Windows上它不是原子的:它只是寻找,然后读取,然后回头。

对于Unix平台,一句话就是pread是任何支持XSI(X / Open System Interface,显然)操作系统的标准:http://www.opengroup.org/onlinepubs/009695399/functions/pread.html

答案 2 :(得分:2)

基于另一个答案,我能想出的最接近的是这个。但是,有一个错误:ReadFile将更改文件偏移量,并且保证pread不会更改文件偏移量。没有真正的方法来解决这个问题,因为代码可以在没有锁的情况下同时执行正常的read()和write()。有人发现了一个不会改变偏移量的电话吗?

unsigned int FakePRead(int fd, void *to, std::size_t size, uint64_offset) {
  // size_t might be 64-bit.  DWORD is always 32.
  const std::size_t kMax = static_cast<std::size_t>(1UL << 31);
  DWORD reading = static_cast<DWORD>(std::min<std::size_t>(kMax, size));
  DWORD ret;
  OVERLAPPED overlapped;
  memset(&overlapped, 0, sizeof(OVERLAPPED));
  overlapped.Offset = static_cast<DWORD>(off);
  overlapped.OffsetHigh = static_cast<DWORD>(off >> 32);
  if (!ReadFile((HANDLE)_get_osfhandle(fd), to, reading, &ret, &overlapped)) {
    // TODO: set errno to something?
    return -1;
  }
  // Note the limit to 1 << 31 before.
  return static_cast<unsigned int>(ret);
}