新規記事の投稿を行うことで、非表示にすることが可能です。
2014年05月30日
サーバ方式ではないログの多重追記方式を考えてみる
同じログ出力ライブラリを使用していて、たまたま同じファイル名になる場合というのも、結構あったりする
こうした際、通常は先にログファイルをオープンしている方が排他的にファイルに書き込むことができえるわけだ
ところが、こうした方式の場合、同じファイル名だと、後から書こうとしていたプロセスのログが失われててしまう
度々非同期に呼ばれるコマンドが、同じログファイルを使用していると、こうしたことになってしまい、後から解析するのに困ってしまうわけだ
とりあえず、Win32 に限って考えてみると、 LockFile API が何となく使えそうな気がした
例えば次のようなインタフェースでログを書くとする
書き込み動作の最終インターフェースがこうした形式であれば、ファイルの最後の領域をロックして、そのロックした両機に指定サイズのデータを書き込めば、うまくいくのではないかと思えた
そこで、次のようなコードを考えてみた
一見これでうまく行きそうに見えたのだが、残念ながらうまくいかず、ファイルの書き込みがオーバーラップしてしまっていた
重なった領域はロックできないと思ったのだが、先頭部分のロック獲得ループがあっさりと抜けてしまい、前のプロセスの書き込み途中から上書きするようになってしまった
もう少し工夫しないといけなさそうだ
こうした際、通常は先にログファイルをオープンしている方が排他的にファイルに書き込むことができえるわけだ
ところが、こうした方式の場合、同じファイル名だと、後から書こうとしていたプロセスのログが失われててしまう
度々非同期に呼ばれるコマンドが、同じログファイルを使用していると、こうしたことになってしまい、後から解析するのに困ってしまうわけだ
とりあえず、Win32 に限って考えてみると、 LockFile API が何となく使えそうな気がした
例えば次のようなインタフェースでログを書くとする
void write(void* buffer, size);
書き込み動作の最終インターフェースがこうした形式であれば、ファイルの最後の領域をロックして、そのロックした両機に指定サイズのデータを書き込めば、うまくいくのではないかと思えた
そこで、次のようなコードを考えてみた
void CWin32Logger::write(void* buffer, DWORD size)
{
DWORD dwSize = GetFileSize(m_hFile, NULL);
while (!LockFile(m_hFile, dwSize, 0, size, 0)) {
Sleep(10);
dwSize = GetFileSize(m_hFile, NULL);
}
if (INVALID_SET_FILE_POINTER != SetFilePointer(m_hFile, 0, NULL, FILE_END)) {
DWORD sz;
if (WriteFile(m_hFile, buffer, size, &sz, NULL)) {
m_dwLoPos = dwSize + size;
FlushFileBuffers(m_hFile);
SetEndOfFile(m_hFile);
}
} else {
TCHAR msg[256] = {0};
wsprintf(msg, _T("%d\r\n"), GetLastError());
OutputDebugString(msg);
}
UnlockFile(m_hFile, dwSize, 0, size, 0);
}
一見これでうまく行きそうに見えたのだが、残念ながらうまくいかず、ファイルの書き込みがオーバーラップしてしまっていた
重なった領域はロックできないと思ったのだが、先頭部分のロック獲得ループがあっさりと抜けてしまい、前のプロセスの書き込み途中から上書きするようになってしまった
もう少し工夫しないといけなさそうだ
2014年05月29日
Shell_NotifyIcon がエラー 0 を返す
PC起動時に動き出すプログラムを開発しているが、通知エリア(昔はタスクトレイとも言っていた) にアイコンを登録するために Shell_NotifyIcon API を使用するが、PC起動時の忙しい時には、結構失敗していることがわかった
http://nyaruru.hatenablog.com/entry/20071008/p3 でも紹介されていたが、 API が FALSE を返したときに GetLastError() でエラーコードを取得すると、 ERROR_TIMEOUT (1460) が返ると説明されているが、自分のプログラムのログを調べると、ERROR_SUCCESS (0) が返ってきており、よくわからない状況となっている
実際上、想像するに、アプリケーション全体がハングアップするのを防ぐ目的で、タイムアウトしているというのが起きているのは間違いないだろうと思っているのだが、 Windows 7 になってからなのか、ERROR_SUCCESS が返ってきているのに違和感を覚えている
いずれにせよエラーには違いないのだろうから、リトライするなどの処置が必要とは思うが、アイコンの変更だけで何秒も待たさせるのも嫌な話だ
今のところは適当に5回程度リトライしてもだめなら、ログを出して無視するという対処にしてあるが、こういうのが解決することはあるのだろうか?
http://nyaruru.hatenablog.com/entry/20071008/p3 でも紹介されていたが、 API が FALSE を返したときに GetLastError() でエラーコードを取得すると、 ERROR_TIMEOUT (1460) が返ると説明されているが、自分のプログラムのログを調べると、ERROR_SUCCESS (0) が返ってきており、よくわからない状況となっている
実際上、想像するに、アプリケーション全体がハングアップするのを防ぐ目的で、タイムアウトしているというのが起きているのは間違いないだろうと思っているのだが、 Windows 7 になってからなのか、ERROR_SUCCESS が返ってきているのに違和感を覚えている
いずれにせよエラーには違いないのだろうから、リトライするなどの処置が必要とは思うが、アイコンの変更だけで何秒も待たさせるのも嫌な話だ
今のところは適当に5回程度リトライしてもだめなら、ログを出して無視するという対処にしてあるが、こういうのが解決することはあるのだろうか?