Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Ведение лога в многопоточном приложении


Страницы:   1 2 3

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.


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо