【问题标题】:Are there equivalents to pread on different platforms?是否有在不同平台上预读的等价物?
【发布时间】:2009-04-20 00:19:44
【问题描述】:

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

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

因此,偏执的解决方案是每个线程有一个打开的文件句柄。现在我有很多文件句柄指向同一个文件,我认为这不是很好。

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

但是,该功能仅在linux上可用,我需要在windows、aix、solaris和hpux上等效的实现,有什么建议吗?

【问题讨论】:

  • 为什么不能为其他平台编写自己的pread()?似乎没有什么是 fseek() 类型函数不能做的。
  • @Duck:Snazzer 想要的是在一个原子操作中寻找和读取的东西。
  • 手册页没有表明 pread() 这样做。任何系统都会在常规文件上提供原子查找/读取吗?即使使用 pread() 他也必须在调用它之前提供自己的锁
  • pread 将偏移量作为参数,所以我假设它允许在共享文件句柄上进行原子查找然后读取/写入操作。谷歌搜索似乎表明......或者我错过了什么?否则,如果 pread 不能用于多线程,它似乎没什么用处。
  • @Snazzer:我很抱歉。它是原子的,实际上很酷。我需要多玩一点。

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


【解决方案1】:

在 Windows 上,ReadFile() 函数可以做到,见lpOverlapped 参数和this info on async IO

【讨论】:

  • 看起来这样可行,似乎即使是同步文件访问,overlapped 参数仍然使用。谢谢 jpalecek!
【解决方案2】:

对于 NIO,java.nio.channels.FileChannel 有一个 read(ByteBuffer dst, long position) 方法,该方法在内部使用 pread

哦,等等,您的问题是关于 C++,而不是 Java。好吧,我只是查看了 JDK 源代码,看看它是如何在 Windows 上运行的,但不幸的是,在 Windows 上它不是原子的:它只是搜索,然后读取,然后再搜索。

对于 Unix 平台,关键是 pread 是任何支持 XSI(显然是 X/开放系统接口)操作系统的标准:http://www.opengroup.org/onlinepubs/009695399/functions/pread.html

【讨论】:

    【解决方案3】:

    根据另一个答案,我能想到的最接近的是这个。但是有一个bug: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);
    }
    

    【讨论】:

    • FWIW,我能够确认 ReadFile() 确实改变了文件偏移量,至少在 Windows 7 上是这样。我使用 SetFilePointerEx() 来读取偏移量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-28
    • 2018-03-16
    • 1970-01-01
    • 1970-01-01
    • 2010-12-07
    相关资源
    最近更新 更多