5

現在、ファイルをディスクに安全に書き込むために、ping/pong バッファリング スキームを実装しています。Linux/CentOS マシンで C++/Boost を使用しています。現在、ファイルの実際のディスクへの書き込みを強制するという問題に直面しています。ファイルシステム (ext3/ext4) / SO カスタム ルール / RAID コントローラ / ハードディスク コントローラのすべてのキャッシング ポリシーに関係なく、これを行うことは可能ですか?

プレーンな fread()/fwrite()、c++ ostream、または boost ファイルシステムを使用するのが最善ですか?

ファイルを単にフラッシュする (fflush()) だけでは、実際の書き込みが保証されないと聞いたことがあります。

4

3 に答える 3

7

fflush (FILE* の場合)、std::flush (IOStream の場合) を使用して、プログラムを強制的に OS に送信します。

POSIXには

  • sync(2) を使用して、そのバッファーへの書き込みをスケジュールするように依頼しますが、書き込みが完了する前に戻ることができます (Linux は、戻る前にデータがハードウェアに送信されるのを待っています)。

  • fsync(2) は、データがハードウェアに送信されるのを待つことが保証されていますが、ファイル記述子が必要です (fileno(3) を使用して FILE* から取得できます。 IOストリーム)。

  • open(2) へのフラグとしての O_SYNC。

いずれの場合も、ハードウェアには独自のバッファがある可能性があります (ただし、制御できる場合、適切な実装ではそれらもフラッシュしようとし、一部のディスクはコンデンサを使用しているため、電源に何が起こってもフラッシュできるようになります)およびネットワーク ファイル システムには、独自の注意事項があります。

于 2012-11-13T09:44:11.653 に答える
2

fsync()/ fdatasync ()を使用して、データをストレージに強制(注1)することができます。それらは、例えばopen()によって与えられるように、ファイル記述子を必要とします。Linuxのマンページには、特にfsyncとfdatasyncの違いに関するLinux固有の情報があります。

ファイル記述子を直接使用しない場合、多くの抽象化には、プロセスに存在する内部バッファーが含まれます。

たとえば、FILE *を使用する場合は、最初にアプリケーションからデータをフラッシュする必要があります。

//... open and write data to a FILE *myfile
fflush(myfile);
fsync(fileno(myfile));
  • 注1:これらの呼び出しにより、OSは、OSキャッシュ内のすべてのデータがドライブに書き込まれるようにし、ドライブはその事実を確認します。多くのハードドライブはこれについてOSに嘘をついており、ドライブのキャッシュメモリにデータを詰め込む可能性があります。
于 2012-11-13T10:00:51.800 に答える
0

標準 C++ にはありません。Unixopenのフラグのように、ある種のシステム固有の IO を使用する必要があります。O_SYNCwrite

ostream(および C では、FILE*) がバッファリングされるという事実によって、これは部分的に暗示的であることに注意してください。何かがいつディスクに書き込まれるか正確にわからない場合、書き込みのトランザクションの整合性を主張してもあまり意味がありません。(ただし、明示的なフラッシュを実行した場合にstreambufのみ書き込みを行うを設計することはそれほど難しくありません。)

編集:

簡単な例として:

class SynchronizedStreambuf : public std::streambuf
{
    int myFd;
    std::vector<char> myBuffer;

protected:
    virtual int overflow( int ch );
    virtual int sync();

public:
    SynchronizedStreambuf( std::string const& filename );
    ~SynchronizedStreambuf();
};

int SynchronizedStreambuf::overflow( int ch )
{
    if ( myFd == -1 ) {
        return traits_type::eof();
    } else if ( ch == traits_type::eof() ) {
        return sync() == -1 ? traits_type::eof() : 0;
    } else {
        myBuffer.push_back( ch );
        size_t nextPos = myBuffer.size();
        myBuffer.resize( 1000 );
        setp( &myBuffer[0] + nextPos, &myBuffer[0] + myBuffer.size() );
        return ch;
    }
}

int SynchronizedStreambuf::sync()
{
    size_t toWrite = pptr() - &myBuffer[0];
    int result = (toWrite == 0 || write( myFd, &myBuffer[0], toWrite ) == toWrite ? 0 : -1);
    if ( result == -1 ) {
        close( myFd );
        setp( NULL, NULL );
        myFd = -1;
    } else {
        setp( &myBuffer[0], &myBuffer[0] + myBuffer.size() );
    }
    return result;
}

SynchronizedStreambuf::SynchronizedStreambuf( std::string const& filename )
    : myFd( open( filename.c_str(), O_WRONLY | O_CREAT | O_SYNC, 0664 ) )
{
}

SynchronizedStreambuf::~SynchronizedStreambuf()
{
    sync();
    close( myFd );
}

(これは表面的にしかテストされていませんが、基本的な考え方はそこにあります。)

于 2012-11-13T09:57:57.670 に答える