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'. Может быть проблема и не в добавлении в лог, но сейчас пересматриваю весь код и возникла мысль, что коллизии могут возникать и в этом месте.
Подскажите как правильно организовать вывод информации?


Суслик   (2007-02-21 16:33:00) [21]

2Coller

Для того, чтобы сильно продвинуться в многопоточности нужно:
1. что-то почитать
2. обязательно смотреть код.

мне в свое время очень помогло изучение *кода* класса TMultiReadExclusiveWriteSynchronizer.

Очень ставит мозги. Я не все понял, конечно, но полезно однозначто было.


Cooller   (2007-02-21 16:24:00) [22]

2 Суслик

Спасибо за советы. Буду разбираться.
А что не все так просто я понял когда еще несколько лет назад знакомился с ASM и необходимо было подменять вектора прерываний. Правда тогда все решалось использованием cli и sti =)


Суслик   (2007-02-21 15:59:00) [23]


> [12] Leonid Troyanovsky ©   (21.02.07 12:58)
> А зачем в форме? Richedit вполне понимает EM_*.
> Которые ему SendMessage, конечно.


Согласен. Но мой вариант имхо более гобок, т.к. перед добавлением может понадобиться доп. обработка.
К тому же я winapi плохо знаю, чтобы советовать события контролам кидать :)


Суслик   (2007-02-21 15:55:00) [24]

Поставь себе средство какое-нибудь, чтобы стек вызовов при исключении показывало. Можешь в jedi покопаться - я иногда этим пользуюсь.

----------

Общее правило таково. Многопоточное программирование сильно отличается от однопоточного в части философии. В таком программировании могут быть всякие разные неожиданные эффекты. Не всегда доступ из нескольких потоков БЕЗ синхронизации запрещен. Например ты спокойно можешь обращаться и менать глоб. булеву переменную без всякой синхронизации. Если не ошибаюсь, то и integer можешь. А вот int64 уже нет, ибо она делается двумя машинными командами.

Это я к тому, что многопоточное программирование просто так снаскока не возьмешь. Нужно читать, изучать чужой код (да хоть тот же TThread и прочие многопоточные вещи из rtl и vcl). Можешь Рихтера почитать - программирование в win32. У него много про межпоточнкую синхронизацию - мозги точно разовьешь.

-----
Я понимаю, что у тебя конкретная проблема. Но и решение ее должно быть кокретно. Т.е. что-либо внятное дистанционно сказать сложно.

-----
Приведенный выше код с крит. секциями не очень хорош лучше так

unit LogSupport;

interface

procedure Log(const AMsg:string; const AParam:string = '');

implementation

uses Classes, SysUtils, SyncObjs;

var LogName:string;
  cs : TCriticalSection = nil;

procedure Log(const AMsg : string; const AParam : string = '');
var
F:Text;
begin
cs.Enter;
try
 Assign(F,LogName);
 if FileExists(LogName) then Append(F) else Rewrite(F);
 try
  Writeln(F,FormatDateTime('dd.mm.yyyy hh:mm:ss',Now),#9,AMsg,#9,AParam);
 finally
  Close(F);
 end;
finally
 cs.Leave;
end;
end;

initialization
cs := TCriticalSection.Create;
LogName:=ChangeFileExt(ParamStr(0),'.log');
finalization
cs.Free;
end.


Cooller   (2007-02-21 15:41:00) [25]

Просто программа хоть и не большая, но кода все-таки на 1500 строк. Вроде бы закрыл все "критические" места, но все равно получаю Access Violation. Даже и не знаю как выловить причину.


Cooller   (2007-02-21 15:34:00) [26]

Вообще какие бы могли дать общие советы? Использовать как можно меньше глобальный переменных? В некоторых случаях они необходимы, получается потоки должны работать с ними только с синхронизацией? Или в общем случае она не нужна, а есть только некоторые исключения?


Reindeer Moss Eater   (2007-02-21 15:06:00) [27]

то не "жирно" ли каждый раз вызывать FileExists? =)

А там прикинь, еще каждый раз с объектом синхронизации телодвижения  вставлены. Вообще кошмар.


Суслик   (2007-02-21 15:04:00) [28]

проведи анализ - используй QueryPerformanceFrequency и QueryPerformanceCounter и пойми, сколько времени занимает вызов FileExists в общем времени работы алгоритма.


Cooller   (2007-02-21 15:01:00) [29]

2 Reindeer Moss Eater
Может дурацкий вопрос, но у меня почему-то на эту тему постоянная паранойя (после некоторых лекций в универе). Если Log, к примеру, вызывается по 5 раз в секунду, то не "жирно" ли каждый раз вызывать FileExists? =)


Reindeer Moss Eater   (2007-02-21 13:05:00) [30]

unit LogSupport;

interface

procedure Log(const AMsg:string; const AParam:string = '');

implementation

uses Classes, SysUtils, SyncObjs;

var LogName:string;
   cs : TCriticalSection = nil;

procedure Log(const AMsg : string; const AParam : string = '');
var F:Text;
begin
cs.Enter;
Assign(F,LogName);
try
 if FileExists(LogName) then Append(F) else Rewrite(F);
 Writeln(F,FormatDateTime('dd.mm.yyyy hh:mm:ss',Now),#9,AMsg,#9,AParam);
finally
 Close(F);
 cs.Leave;
end;
end;

initialization
cs := TCriticalSection.Create;
LogName:=ChangeFileExt(ParamStr(0),'.log');
finalization
cs.Free;
end.


Leonid Troyanovsky   (2007-02-21 12:58:00) [31]


> Суслик ©   (21.02.07 11:57) [11]

> 2 При доступе к richedit используй postmessage. событие
> лови в форме.

А зачем в форме? Richedit вполне понимает EM_*.
Которые ему SendMessage, конечно.

--
Regards, LVT.


Суслик   (2007-02-21 11:57:00) [32]

1 Используй критические секции при доступе к файлу.
2 При доступе к richedit используй postmessage. событие лови в форме. только договорись о том, как данные (строки) передавать.


Хинт   (2007-02-21 10:36:00) [33]


> Ну можно, только нужно хорошо понимать, что делаешь. Только
> вопрос - зачем.

В [2] я описал ситуацию.  Synchronize это ведь метод TThread...


DrPass   (2007-02-21 10:30:00) [34]


> вместо synchronize можно использовать sendmessage?

Можно и так. Или PostMessage. С точки зрения производительности - более эффективный вариант


Суслик   (2007-02-21 10:27:00) [35]

Ну можно, только нужно хорошо понимать, что делаешь.
Только вопрос - зачем.
synchronize реализован как раз на одном из методов (postmessage or sendmessage - зависит от версии дельфи).

причем они это сделали очень неплохо - весьма продуманный код.
я бы тебе не советовал делать такую синхронизацию самому.


Cooller   (2007-02-21 09:57:00) [36]

2 Суслик
Спасибо за ответ. Хотел спросить еще одну вещь... вместо synchronize можно использовать sendmessage?


Суслик   (2007-02-21 02:17:00) [37]


> Cooller   (20.02.07 23:51) [5]

ну ситуация такова.
vcl не является многопоточной. если ты хочешь вызвать метод из библиотеки vcl (читай из визуального компонента), то ты обязан это делать в контексте основного потока. для того, чтобы выполнить код из доп. потока в контексте основного потока тебе нужно использовать метод synchronize из класса tthread.

вообще использование vcl из разных потоков без синхронизации не обязательно влечет av. но делать этого все же нельзя - ибо vcl не спроектирована как многопоточная.

вполне возможно, что у тебя есть некоторые другие ошибки в программе, приводящие к av.

для синхронизации общих данных используй критические секции.


Cooller   (2007-02-20 23:51:00) [38]

В том и дело, что ошибки другого рода, которые проявляются через Access Violation. Для того, чтобы понять как их устранить - я и создал тему.


Cooller   (2007-02-20 23:50:00) [39]


> Выкинь отовсюду  try except end и начни исправлять свои
> баги.


Если бы они были, то конструкция хотя бы иногда срабатывала


Loginov Dmitry   (2007-02-20 23:25:00) [40]

> Так вот, несмотря на то, что у меня во всех процедурах и
> функциях стоят оработчики try except end, с выводом сообщения
> об ошибке в лог, периодически получаю 'Access Violation'.


Выкинь отовсюду  try except end и начни исправлять свои баги.


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

Наверх

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