2009-04-20 113 views
3

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

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

所以,偏执的解决方案是每个线程有一个打开的文件句柄。现在我对同一个文件有很多文件句柄,我认为它不会很好。

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

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

+0

为什么不能为其他平台编写自己的pread()? fseek()类型的函数似乎没有什么不可以做的。 – Duck 2009-04-20 00:57:59

+1

@Duck:Snazzer想要的是在一次原子操作中寻找和阅读的东西。 – 2009-04-20 01:55:12

+0

手册页不会指出pread()会这样做。任何系统是否会提供对普通文件的原子查找/读取?即使使用pread(),他也必须在调用它之前提供自己的锁 – Duck 2009-04-20 02:11:44

回答

4

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

哦,等等,你的问题是关于C++,而不是Java。那么,我只是看了看JDK源代码,看看它是如何用于Windows的,但不幸的是,在Windows上它不是原子的:它只是查找,然后读取,然后找回。

对于Unix平台,点睛之笔是pread为任何XSI支撑(在X/Open系统接口,显然)操作系统标准:http://www.opengroup.org/onlinepubs/009695399/functions/pread.html

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); 
} 
相关问题