スレッドセーフな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機能で簡単に実行できます。
ヒントをいただければ幸いです。よろしくお願いします!