![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Ведение лога в многопоточном приложении
Cooller © (2007-02-20 22:52:00)Есть серверное приложение, активно работающая одновременно с несколькими клиентами. Некоторые события необходимо выводить в лог (как в файл, так и в RichEdit).
Вот сама процедура:
procedure ATL(msg:string; showmsg:boolean=false);
begin
try
Append(F);
WriteLn(F,DateTimeToStr(now)+': '+msg);
CloseFile(F);
except
end;
end;
FormCreate:
AssignFile(F,opt.curlogname);
{$I-}
Append(F);
{$I+}
If IOResult<>0 then Rewrite(F);
CloseFile(F);
В RichEdit добавляю просто с помощью Lines.Add
Так вот, несмотря на то, что у меня во всех процедурах и функциях стоят оработчики try except end, с выводом сообщения об ошибке в лог, периодически получаю 'Access Violation'. Может быть проблема и не в добавлении в лог, но сейчас пересматриваю весь код и возникла мысль, что коллизии могут возникать и в этом месте.
Подскажите как правильно организовать вывод информации?
Leonid Troyanovsky (2007-02-25 08:13:00) [1]
> Игорь Шевченко © (25.02.07 00:40) [41]
> или я какой-то простой и легкий способ упустил ?
Легких я тоже не знаю. Через сабклассирование или хуком.
Но, с другой стороны, если для контроля валидности
удерживаемого хендла окна чужого приложения нам нужен хук,
то почему б в своем приложении не делать тоже самое.
--
Regards, LVT.
Игорь Шевченко (2007-02-25 00:40:00) [2]Leonid Troyanovsky © (24.02.07 23:56) [40]
> Синхронное, асинхронное - все возможно.
> Главное, что оно не пересоздается.
И все-таки, может, я чего не до конца понимаю, но каким образом ты предлагаешь обрабатывать синхронные сообщения посланные окну Application.Handle ? Через подмену его WndProc или я какой-то простой и легкий способ упустил ?
Leonid Troyanovsky (2007-02-24 23:56:00) [3]
> Игорь Шевченко © (24.02.07 20:12) [39]
> > Для исключения достаточно отправлять сообщение окну
> > Application, которое никогда не пересоздается.
> А если требуется отправить синхронное сообщение ?
Синхронное, асинхронное - все возможно.
Главное, что оно не пересоздается.
--
Regards, LVT.
Игорь Шевченко (2007-02-24 20:12:00) [4]Leonid Troyanovsky © (22.02.07 19:55) [36]
> Для исключения достаточно отправлять сообщение окну
> Application, которое никогда не пересоздается.
А если требуется отправить синхронное сообщение ?
Чапаев (2007-02-22 20:23:00) [5]Тьфу, блин. Через ReportEvent().
Чапаев (2007-02-22 20:23:00) [6]А я бы всё это через EventLog() писал в системный журнал, а потом при необходимости выборку в файл делал...
Leonid Troyanovsky (2007-02-22 19:55:00) [7]
> Игорь Шевченко © (22.02.07 12:14) [32]
> Для исключения подобной ситуации, мне кажется, лучше будет
> отправлять сообщение самой форме, на которой находится контрол
> для протокола, чтобы она в своем потоке добавляла в протокол.
Для исключения достаточно отправлять сообщение окну
Application, которое никогда не пересоздается.
> Но вот стоит ли овчинка выделки (дополнительного кода)
Трудно сказать.
Т.к., между оптимистическим и пессемистическим подходом -
бездна промежуточных.
Вообще-то, предназначение моего комментария было лишь в том,
чтобы заметить, что в случае с многими потоками все оказывается
несколько сложней, чем могло бы показаться.
--
Regards, LVT.
Суслик (2007-02-22 13:43:00) [8]Писать нужно так (имхо, конечно) как знаешь. Если знаешь одну какую-то методику хорошо - ей и нужно пользоваться. Вполне возможно, что прийдет время относительного затишься, когда можно пересмотреть код, сделать необходимый рефакторинг и подумать о сокращении или украшении кода. Но если ты в потоке и делаешь конкретную задачу нужно, то пользоваться проверенными методами.
Игорь Шевченко (2007-02-22 13:12:00) [9]Суслик © (22.02.07 13:02) [33]
Это требует дополнительного кода. А оно надо ?
Суслик (2007-02-22 13:02:00) [10]Я бы предпочел посылку форме, ибо это не трубует доп. знаний vcl в части ее особенности работы в многопоточном режиме.
Игорь Шевченко (2007-02-22 12:14:00) [11]Leonid Troyanovsky © (22.02.07 11:48) [31]
> Можно представить себе ситуацию, когда, скажем при RecreateWnd,
>
> Handle = 0, и вызов приведет к созданию окна во вторичном
> потоке.
> Я бы здесь предпочел передачу в поток самого значения хендла.
>
И что будет с переданным значением Handle после RecreateWnd ?
Сообщения будут отправляться в воздух ?
Для исключения подобной ситуации, мне кажется, лучше будет отправлять сообщение самой форме, на которой находится контрол для протокола, чтобы она в своем потоке добавляла в протокол. Но вот стоит ли овчинка выделки (дополнительного кода) - не уверен.
Leonid Troyanovsky (2007-02-22 11:48:00) [12]
> Игорь Шевченко © (21.02.07 16:33) [22]
> SendMessage(FLog.Handle, LB_ADDSTRING, 0, Integer(PChar(IntToStr(I))));
Тут есть один ньюанс, как-то здесь обсуждался.
Можно представить себе ситуацию, когда, скажем при RecreateWnd,
Handle = 0, и вызов приведет к созданию окна во вторичном потоке.
Я бы здесь предпочел передачу в поток самого значения хендла.
Ну, а если необходимо следить за валидностью этого хендла,
понадобится сабкласирование контрола для ловли WM_DESTROY.
Или же установить хук на первичный поток.
--
Regards, LVT.
Игорь Шевченко (2007-02-21 17:40:00) [13]
> Посмотрел исходники - не первый раз убеждаюсь, что vcl это
> неплохо :)
> Хорошо же они продумали надостройку над winapi - можно напрямую
> пользоваться
Ну да, собственно, еще начиная с первой версии Delphi такие действия были оправданы, так как до того народ кроме api ничего не знал :)
Суслик (2007-02-21 17:26:00) [14]
> [22] Игорь Шевченко © (21.02.07 16:33)
Спасибо, познавательно.
Посмотрел исходники - не первый раз убеждаюсь, что vcl это неплохо :)
Хорошо же они продумали надостройку над winapi - можно напрямую пользоваться, можно через delphi класс.
Суслик (2007-02-21 17:25:00) [15]
> Посоветуйте как лучше передать параметры? Через глобальную
> переменную и сделать критическую секцию? Что-то вроде:
если это sendmessage, то ты можешь передавать указатель в параметрах сообщения. только реши, кто будет данные уничтожать после использования (если это надо).
Cooller (2007-02-21 17:25:00) [16](WM_SYNC_MSG=WM_SYNC_ADD_INFO)
Cooller (2007-02-21 17:23:00) [17]Во многих местах происходит вызов вот этой процедуры:
procedure TfrmMain.AddInfo(Text: string; Color: TColor = clBlack; AddText: string = ''; dbg:boolean=false);
Хочу её тело скопировать в другую, а тут же сделать вызов SendMessage. Посоветуйте как лучше передать параметры? Через глобальную переменную и сделать критическую секцию? Что-то вроде:
private
{ Private declarations }
procedure WMSyncMessage(var Msg: TMessage); message WM_SYNC_MSG;
...
const
WM_SYNC_MSG = WM_USER+...;
...
var
ai:record
...
end;
...
procedure TfrmMain.AddInfo(Text: string; Color: TColor = clBlack; AddText: string = ''; dbg:boolean=false);
SLock.Enter;
try
ai.text:=text;
ai.color:=color;
ai.addtext:=addtext;
ai.dbg:=dbg;
SendMessage(frmMain.Handle,WM_SYNC_ADD_INFO,0,0);
finally
SLock.Leave;
end;
end;
procedure TfrmMain.WMSyncMessage(var Msg: TMessage);
begin
SyncAddInfo(ai.text,ai.color,ai.addtext,ai.dbg);
end;
Cooller (2007-02-21 17:23:00) [18]Во многих местах происходит вызов вот этой процедуры:
procedure TfrmMain.AddInfo(Text: string; Color: TColor = clBlack; AddText: string = ''; dbg:boolean=false);
Хочу её тело скопировать в другую, а тут же сделать вызов SendMessage. Посоветуйте как лучше передать параметры? Через глобальную переменную и сделать критическую секцию? Что-то вроде:
private
{ Private declarations }
procedure WMSyncMessage(var Msg: TMessage); message WM_SYNC_MSG;
...
const
WM_SYNC_MSG = WM_USER+...;
...
var
ai:record
...
end;
...
procedure TfrmMain.AddInfo(Text: string; Color: TColor = clBlack; AddText: string = ''; dbg:boolean=false);
SLock.Enter;
try
ai.text:=text;
ai.color:=color;
ai.addtext:=addtext;
ai.dbg:=dbg;
SendMessage(frmMain.Handle,WM_SYNC_ADD_INFO,0,0);
finally
SLock.Leave;
end;
end;
procedure TfrmMain.WMSyncMessage(var Msg: TMessage);
begin
SyncAddInfo(ai.text,ai.color,ai.addtext,ai.dbg);
end;
novill (2007-02-21 16:36:00) [19]а как насчет использования
flush
или
CreateFileс флагом FILE_FLAG_WRITE_THROUGH
Игорь Шевченко (2007-02-21 16:33:00) [20]
> К тому же я winapi плохо знаю, чтобы советовать события
> контролам кидать
А собственно это тот же Рихтер описывает. SendMessage блокирует отправляющий поток до тех пор, пока принимающий не обработает сообщение.
Следующий код вполне себе работает (мне проще в ListBox отправлять :)
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
ListBox1: TListBox;
btnNew: TButton;
procedure btnNewClick(Sender: TObject);
end;
var
Form1: TForm1;
implementation
uses
Thread;
{$R *.dfm}
procedure TForm1.btnNewClick(Sender: TObject);
begin
TFooThread.Create(ListBox1);
end;
end.
unit thread;
interface
uses
Classes, StdCtrls;
type
TFooThread = class(TThread)
private
FLog: TListBox;
protected
procedure Execute; override;
public
constructor Create (ALog: TListBox);
end;
implementation
uses
Windows, Messages, SysUtils;
{ TFooThread }
constructor TFooThread.Create(ALog: TListBox);
begin
FLog := ALog;
inherited Create (false);
end;
procedure TFooThread.Execute;
var
I: Integer;
begin
I := 0;
while not Terminated do begin
SendMessage(FLog.Handle, LB_ADDSTRING, 0, Integer(PChar(IntToStr(I))));
Inc(I);
Sleep(100);
end;
end;
end.