我在C ++中编写一个并发的持久性消息队列,它需要对文件进行并发读访问,而不使用内存映射io。简短的故事是,几个线程需要从文件的不同偏移量中读取。
最初我有一个具有典型读/写方法的文件对象,并且线程会获取一个互斥锁来调用这些方法。但是,碰巧我没有在某处正确获取互斥锁,导致一个线程在读/写期间移动文件偏移量,另一个线程将开始读/写文件的错误部分。
因此,偏执的解决方案是每个线程有一个打开的文件句柄。现在我对同一个文件有很多文件句柄,我假设它不是很好。
我想使用类似pread的东西,它允许将当前偏移传递给读/写函数。
但是,该功能仅适用于linux,我需要在windows,aix,solaris和hpux上有相应的实现吗?
答案 0 :(得分:6)
在Windows上,ReadFile()功能可以执行此操作,请参阅lpOverlapped
参数和this info on async IO。
答案 1 :(得分:4)
使用NIO,java.nio.channels.FileChannel
有read(ByteBuffer dst, long position)
方法,内部使用pread
。
对于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);
}