2nd
Дек

Как правильно организовывать лог-файл в многопоточных приложениях?

Posted by Chas under Delphi

Вопрос в следующем:
как правильно организовать ведение лога в многопоточном приложении?

Передомной n число проблем:
1. Хреналион потоков одновременно вызовет сброс данных в файл.
2. Как и когда организовывать сброс данных в файл?
3. как вообще правильно сбрасывать данные в файл?

Сайчас у меня это организовано следующим образом:
Есть некий обьект TObject, далее есть хранилище этих обьектов TList.
Всё это связано с ListView(Ну отображение), сброс в файл происходит после каждого вызова «добавить запись в лог».

НО думаю хранение хреналиардов Object в Tlist пагубно сказывается на ОЗУ ПК где работает программа. Особенно, когда прорамма работает несколько месяцев.

В общем я в тупике по поводу этого…
Сейчас пытаюсь связать всё это дело с XML файлами.

А задачи такие:
1. собирать и сохранять всю информацию.
2. ничего не растерять при падении программы.(Программа навернулась, однако в логе данные есть хотябы за прошедшие 5 секунд).

veniside
Я уже приводил этот код. За последние пол-года в нём только допилена совместимость с x64. Типы int и unsigned объявлены как 32/64, в зависимости от проца.

var
g_logOL: array[byte] of OVERLAPPED; // array of OL
g_logOLOffs: int; // offset of next OL operation
g_logOLEvents: array[byte] of tHandle; // array of OL event handles
g_logOLBufs: array[byte] of pointer; // array of OL buffers
g_logOLBufsSz: array[byte] of int; // array of OL buffer sizes
g_logOLCount: int; // number of OLs

// -- --
function incMT(var v: int; delta: int): int;
begin
result := InterlockedExchangeAdd(v, delta);
end;

// -- --
function write2file(handle: tHandle; var offset: int; buf: pointer; len: unsigned): bool;
var
i: DWORD;
OL: POVERLAPPED;
ofs: unsigned;
begin
result := false; //
if ((0 < len) and (nil <> buf)) then begin
//
ofs := incMT(offset, len);
//
// find non-pending OL
i := 0;
if (0 < g_logOLCount) then begin
//
i := WaitForMultipleObjects(g_logOLCount, PWOHandleArray(@g_logOLEvents), false, 10); // do not wait for too long, better create new OL
if (i < WAIT_OBJECT_0 + unsigned(g_logOLCount)) then
OL := @g_logOL
else
OL := nil; // all are busy
end
else
OL := nil;
//
if ((nil = OL) and (g_logOLCount <= high(g_logOL) - low(g_logOL))) then begin
//
i := low(g_logOL) + incMT(g_logOLCount, 1);
g_logOLEvents := CreateEvent(nil, false, false, nil); // auto-reset event
g_logOL.hEvent := g_logOLEvents;
//
OL := @g_logOL;
end;
//
if (nil <> OL) then begin
//
if (int(len) > g_logOLBufsSz) then begin
//
reallocMem(g_logOLBufs, len);
g_logOLBufsSz := len;
end;
//
move(buf^, g_logOLBufs^, len);
//
OL.Offset := ofs and $FFFFFFFF;
{$IFDEF CPUx64 }
OL.OffsetHigh := ofs shr 32;
{$ELSE }
OL.OffsetHigh := 0;
{$ENDIF CPUx64 }
//
result := WriteFile(handle, g_logOLBufs, len, nil, OL);
if (not result and (ERROR_IO_PENDING = GetLastError())) then
result := true // report no error
else
SetEvent(OL.hEvent);
//
end;
end;
end;

// -- --
procedure releaseOLs();
var
i: int;
w: unsigned;
begin
if (0 < g_logOLCount) then begin
//
WaitForMultipleObjects(g_logOLCount, PWOHandleArray(@g_logOLEvents), true, 3000);
//
i := 0;
while (i < g_logOLCount) do begin
//
w := WaitForSingleObject(g_logOLEvents, 10);
if (WAIT_OBJECT_0 = w) then begin
//
CloseHandle(g_logOLEvents);
reallocMem(g_logOLBufs, 0);
end;
//
inc(i);
end;
//
g_logOLCount := 0;
end;
end;

тема на форуме

Похожие статьи