0

基本的にバイナリファイルからベクトルを読み書きするC++クラスがあります。単一のベクトルをメモリにロードする読み取り関数の例は、次のようになります。

int load (const __int64 index, T* values) const {

 int re = _fseeki64(_file, index * _vectorSize + _offsetData, SEEK_SET); 
 assert(re == 0);

 size_t read = fread(values, sizeof(T), _vectorElements, _file);
 assert(read == _vectorElements);

 return 0;}

OutプログラムはOpenMPでマルチスレッド化されており、複数のスレッドが同時に同じファイルにアクセスします。複数のスレッドによる問題を回避するために、OpenMPの重要なステートメント内で関数呼び出しを常にカバーしています。

#pragma omp critical {
    load(...);
}

Microsoft Visual C ++ランタイムには、、などのいくつかの関数が含まれていることを知っています...たとえば、関数は次のように記述されます_fseek_nolock_fread_nolock_fwrite_nolock_fread_nolock()

この関数は、freadの非ロックバージョンです。他のスレッドによる干渉から保護されていないことを除いて、freadと同じです。他のスレッドをロックアウトするオーバーヘッドが発生しないため、より高速になる可能性があります。この関数は、シングルスレッドアプリケーションなどのスレッドセーフなコンテキストで、または呼び出し元のスコープがすでにスレッドの分離を処理している場合にのみ使用してください。

今私の質問:関数が「再入可能」呼び出しをブロックすることを理解しているので、他のスレッドが戻る前に他のスレッドが関数に入ることがありません。しかし、なぜそのように単一の機能を保護する必要があるのか​​理解できません。IMHO(_fileコードサンプル内の)ファイルポインタにアクセス/変更するすべての関数は保護する必要があるため、スレッドセーフにする必要があります。これには、実際に標準のC関数fseekとfreadを呼び出す関数ブロック全体の周りにロックを構築する必要があるため、このような非ブロッキング関数を提供する意味がわかりません。

私たちのパラノイドロックスキームはパフォーマンスをいくらか浪費すると思うので、誰かが私にこれらのロックメカニズムを説明できますか?

前もって感謝します!

4

3 に答える 3

2

一部の単純なコードでは、FILE*内のロックで十分です。すべてのスレッドが共通のファイル*を介してログに記録されるようにする基本的なログインフラストラクチャについて考えてみます。内部ロックにより、FILE *が複数のスレッドによって破損しないようになります。また、各ログ行はスタンドアロンである必要があるため、個々の呼び出しがどのようにインターリーブするかは問題ではありません。

于 2009-12-11T20:09:42.430 に答える
1

MicrosoftマルチスレッドCランタイムを使用する場合、グローバル変数または静的変数を必要とするすべての関数は単純に正しく機能します(printfやfreadなど、グローバルが必要な理由を聞かないでください)。ただし、FILE *構造体を、それに書き込みを行う関数に渡して、スレッドセーフであると期待することはできません。

したがって、マイクロソフトの「スレッドセーフ」機能は、再入可能であるという意味でのみスレッドセーフです。つまり、グローバルおよびスタティックへのすべてのアクセスは、ミューテックスなどを使用して行われます。ただし、同じFILE *を使用して2つのfprintf()を同時に呼び出すことができるという意味ではありません。

ソース: http: //msdn.microsoft.com/en-us/library/1bh5ewb2%28VS.71%29.aspx

于 2009-12-11T20:03:56.973 に答える
0

アプリケーションがすでにファイルハンドルへのシリアル化されたアクセスを保証している場合、c-runtimeにそれ自体のシリアル化をバイパスするように指示すると、パフォーマンスを向上させることができます。これが_fread_nolockなどの関数の目的です。

于 2009-12-22T22:21:54.593 に答える