5

スレッドセーフなCロギング関数を作成しようとしていますが、ファイルIOに深刻な問題があります。したがって、基本的に、バイナリ更新モードでログを開くことができる興味深いfopen呼び出しから始めます。

FILE *log, *start;
int timeout = 0, error;

//make file (fails if file exists)
log = fopen(LOG_FILE, "wx");

//Close the file if a new one was created
if(log)
   fclose(log);

//Open file in update mode (it must exist for this)
log = fopen(LOG_FILE, "rb+");

次に、ファイルをロックし、別のスレッドがファイルを長時間ロックした場合のタイムアウトを組み込みます。

//Init other file pointer
start = log;

//Lock file (with timeout)
rewind(start);
error = lockf(fileno(start), F_TLOCK, 0);
while( error == EACCES || error == EAGAIN)
{
  //sleep for a bit
  usleep(LOCKED_FILE_RETRY_TIME);

  //Incremement timeout
  timeout += LOCKED_FILE_RETRY_TIME;

  //Check for time out
  if(timeout > LOCKED_FILE_TIMEOUT)
  {
     return;
  }

  //Retry the lock operation
  error = lockf(fileno(start), F_TLOCK, 0);
}

そして最後に、必要なメッセージをファイルの最後に追加し、ロックを解除してファイルを閉じます。

//Print log entry
fseek(log, 0, SEEK_END);
fwrite((const void*) log_msg, 1, strlen(log_msg), log);

//Unlock the block
rewind(start);
lockf(fileno(start), F_ULOCK, 0);

//Close file
fclose(log);

fopenただし、メッセージの大部分は、ファイルの「スナップショット」を取得し、ロックが解除されるのを待って、ファイルの最後に書き込まれるかのように、追加されるのではなく、ログに上書きされるようです。別のプロセスがそれに追加されなかった場合になります。誰かが私がこの問題を修正する方法について何か考えを持っていますか?

余談ですが、ログファイルが特定のサイズを超えないようにするトリミング機能を最終的に追加するため、バイナリ更新モードにしたいのですが、これは作業中のfseek呼び出しとR/W機能で簡単に実行できます。

ヒントをいただければ幸いです。よろしくお願いします!

4

1 に答える 1

5

fflush()ロックを解除する前にファイルポインタを呼び出さなかった。fclose()そうすれば、ロックが保持されなくなったときに、ログメッセージがstdioバッファに残り、書き出されます。

この問題を解決するには、ロック解除操作の前に前を追加するか、fflush(log)単にfclose(log)前を移動します。

于 2013-02-15T21:28:50.907 に答える