2012-03-26 27 views
8

複数のプロセスが同じファイルに同時にアクセス(書き込み)することは問題ありませんか?次のコードを使用して、それは動作するようだが、私は疑問を持っています。複数のプロセスが同じファイルにアクセスする

インスタンスのユースケースは、電子メールが受信されるたびに呼び出され、中央ファイルに出力される実行可能ファイルです。

if (freopen(console_logfile, "a+", stdout) == NULL || freopen(error_logfile, "a+", stderr) == NULL) { 
    perror("freopen"); 
} 
printf("Hello World!"); 

これはCentOSの上で実行され、この答えが間違っていたC.

+0

[2つのプロセスを開く]可能な(より良い)複製(http://stackoverflow.com/questions/1842909/fopen-two-processes)。 – blahdiblah

+0

関連項目[複数のプロセスが並行処理の問題を起こさずにfopenを使用してファイルに追加できますか?](http://stackoverflow.com/questions/7552451/can-multiple-processes-append-to-a-file-using-fopen-コンビニエンスなしのprob)。 – blahdiblah

+2

私はあなたのログの使い方のコンテキストを知らないのですが、 'syslog'を見てみることをお勧めします。多分それはあなたに合っています。それを使って作業するのはとても簡単です。 http://www.gnu.org/software/libc/manual/html_node/Submitting-Syslog-Messages.html –

答えて

8

Cの標準IO機能を使用すると、複雑さの新しい層を導入し、ファイルはwrite(2) - システムコール(またはメモリマッピングなど)を介してのみ変更されますが、この場合は使用されません。C標準のIOラッパーはしばらくファイルへの書き込みを延期し、コール。

write(2)コール自体はよく振る舞うべき:

[...] If the file was 
    open(2)ed with O_APPEND, the file offset is first set to the 
    end of the file before writing. The adjustment of the file 
    offset and the write operation are performed as an atomic 
    step. 

    POSIX requires that a read(2) which can be proved to occur 
    after a write() has returned returns the new data. Note that 
    not all file systems are POSIX conforming. 

をこのように、あなたの根本的なwrite(2)呼び出しが正常に動作します。

上位のC標準IOストリームの場合は、バッファリングも処理する必要があります。 setvbuf(3)関数を使用して、バッファリングされていない出力、ラインバッファ出力、またはブロックバッファ出力を要求することができます。デフォルトの動作はストリームごとに変化します - 標準出力と標準エラーが端末に書き込んでいる場合、それらはデフォルトでラインバッファリングされ、バッファリングされません。それ以外の場合は、ブロックバッファリングがデフォルトです。

インターリーブされたデータを防ぐために、データが自然に行指向の場合は、手動でラインバッファを選択することをお勧めします。データがでない場合は、ライン指向の場合は、バッファリングされていないバッファを使用するか、ブロックバッファのままにして、出力の単一の単位を蓄積するたびに手動でデータをフラッシュします。

一度にBUFSIZバイト以上を書き込むと、書き込みがインターリーブされる可能性があります。 setvbuf(3)機能は、インターリーブを防止するのに役立ちます。

パフォーマンスについて話すのは時期尚早かもしれませんが、ラインバッファリングはブロックバッファリングよりも遅くなります。ディスクの速度に近い速度でロギングを行っている場合は、書き込みがインターリーブされないようにするために、別のアプローチをとることもできます。

+0

'setvbuf()'とその変種 'setbuf()'、 'setbuffer()'、 'setlinebuf()'に関する素晴らしいヒントです。彼らは私が必要としていたものでした。ありがとう、@ sarnold。 –

+0

ファイルオフセットのアトミック調整を保証するためにO_APPENDが必要であることを指摘してくれてありがとう。私はそれを作成するので、ファイルを開く最初のプロセスから省略しました(したがって、 'append'は適切ではありませんでした..) – RobM

1

としてコンパイルされます。この作業を行います。

だから、レース条件は次のようになります。

  1. プロセス1は、追記のためにそれを開いて、その後、
  2. 後の処理2追記のためにそれを開いて、その後、
  3. 後にまだ1個の書き込み閉じて、次に
  4. 最後に2つの書き込みと閉じます。

作業が意味するべきことは私には明らかではないので、「働いていれば」感心します。私は '作業中'と書かれたバイトのすべてが、2つのプロセスによって がintheログファイルであると仮定しますか?私は彼らが両方とも と同じバイトオフセットで書き始めると期待しています。したがって、1つは他のバイトを置き換えます バイト。それはすべてまで大丈夫であり、ステップ3を含みます。ステップ4で問題として を表示するだけです。簡単なテストのように見えます:open getchar ...書き込みを閉じる。

ファイルを同時に開くことが重要ですか? A 書き込みが速い場合、より明白な解決方法は、排他的に開くことです。お使いのシステムのクイックチェックのために

、試してみてください。

/* write the first command line argument to a file called foo 
* stackoverflow topic 9880935 
*/ 

#include <stdio.h> 
#include <fcntl.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 

int main (int argc, const char * argv[]) { 
    if (argc <2) { 
     fprintf(stderr, "Error: need some text to write to the file Foo\n"); 
     exit(1); 
    } 

    FILE* fp = freopen("foo", "a+", stdout); 

    if (fp == NULL) { 
     perror("Error failed to open file\n"); 
     exit(1); 
    } 

    fprintf(stderr, "Press a key to continue\n"); 
    (void) getchar();  /* Yes, I really mean to ignore the character */ 

    if (printf("%s\n", argv[1]) < 0) { 
     perror("Error failed to write to file: "); 
     exit(1);   
    } 

    fclose(fp); 

    return 0; 
} 
+0

'man freopen'からお互いを上書きしません:' a + ...それ以降のファイルへの書き込みファイルの現在の終わりに終わります。 – blahdiblah

+0

@blahdiblah - 多分私は何かが欠けているかもしれませんが、どうすれば**私の例で上書きできないのでしょうか?どちらのプロセスもappendのためにオープンしますが、どちらのバイトもそのステージで書き込まないので、ファイルは両方ともオープンされたときに同じ長さになります。それから両方とも書いています。ファイルオフセットはファイルではなくfdの属性ではないのですか? – gbulmer

+0

マニュアルページの情報と私自身のテストの結果だけを報告します。基本的な実装の詳細については言及できません。 – blahdiblah

関連する問題