2009-04-20 9 views
3

私は、メモリマップドioを使用せずにファイルへの同時読み取りアクセスを必要とするC++での永続的なメッセージキューを同時に作成しています。短い話は、いくつかのスレッドがファイルの異なるオフセットから読み取る必要があるということです。異なるプラットフォームで先験的に同等のものがありますか?

私は典型的な読み書きメソッドを持ったファイルオブジェクトを持っていました。スレッドはこれらのメソッドを呼び出すためにミューテックスを取得します。しかし、私はミューテックスをどこかで正しく取得しておらず、あるスレッドが読み込み/書き込み中にファイルのオフセットを移動させ、別のスレッドがファイルの不正な部分に対して読み書きを開始することがありました。

だから、パラノイドの解決策は、スレッドごとに1つのオープンファイルハンドルを持つことです。今、私は同じファイルにたくさんのファイルハンドルを持っています。私はこれが素晴らしいとは限りません。

preadのようなものを使用して、現在のオフセットを読み書き機能に渡すことができます。

しかし、この関数はlinuxでしか利用できません。私はWindows、aix、solaris、hpuxなどの同等の実装が必要ですか?

+0

他のプラットフォーム用に独自のpread()を書くことができないのはなぜですか? fseek()型関数ではできないことはありません。 – Duck

+1

@Duck:Snazzerが望んでいるのは、1つのアトミック操作で検索して読み込むものです。 –

+0

マニュアルページにpread()が表示されていないことが示されています。どのシステムでも、通常のファイルに対してアトミックなシーク/リードが可能ですか? pread()を使用しても、彼は – Duck

答えて

6

ReadFile()機能は、それを行うことができ、lpOverlappedを参照してくださいパラメータはthis info on async IOです。

+1

ニース。私はなぜJDKがそれを使用していないのだろうと思っています.... –

+0

これはうまくいくように見えますが、重複したパラメータは同期ファイルアクセスでも使用されているようです。おかげでjpalecek! – Snazzer

4

NIOの場合、java.nio.channels.FileChannelread(ByteBuffer dst, long position)メソッドを持ち、これは内部でpreadを使用します。

お待ちください、あなたの質問は、JavaではなくC++です。さて、JDKのソースコードを見て、Windows用の方法を見てみましたが、残念なことにWindows上ではアトミックではありません。単純にシークして読み込み、次にシークします。 UNIXプラットフォームの

パンチラインがpreadがどのXSI支持(X /オープンシステムインタフェース、明らかに)オペレーティングシステムの標準であるということです、:Windowsではhttp://www.opengroup.org/onlinepubs/009695399/functions/pread.html

2

もう1つの答えに基づいて、私が思いつく最も近いのはこれです。しかし、バグがあります: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); 
} 
+0

FWIW、私はReadFile()がWindows 7でファイルのオフセットを変更していることを確認できました。私はSetFilePointerEx()を使ってオフセットを読みました。 – kainjow

関連する問題