Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.03.12;
Скачать: CL | DM;

Вниз

Количество потоков всё время растёт?!   Найти похожие ветки 

 
Ksenom   (2006-02-09 10:57) [0]

По работе столкнулся с такой проблемой.

В процессе работы я по таймеру создаю и вызываю поток:

procedure TForm1.StartMaket;
 var Maket:TMaket;
begin
 Maket:=TMaket.Create(true);
 Maket.FreeOnTerminate:=true;
 Maket.Resume;
end;

Сам поток в процессе инициализации запускает функцию:

procedure TMaket.Execute;
begin
 Processing;
end;

Функция, в общих чертах, через Mapi смотрит почту, пишет в базу, отпровляет письма и всё такое. Факт что процедура без проблем и ошибок выполняется до конца. Таким образом по идее после её выполнения поток должен уничтожиться и освободить занимаемую им память.

За сутки работы (каждые 10 минут старт потока) количество потоков с 3 увеличивается до 9 и продолжает медленно расти. При этом ошибок нет, так как я в сами потоки запихал много проверок на ошибки. Более того растёт объём занимаемой программой в системе памяти. С 3 Мб при старте за сутки вырастает до 25Мб.

Почему так и как с этим бороться?


 
Digitman ©   (2006-02-09 11:09) [1]


> Факт что процедура без проблем и ошибок выполняется до конца


Не факт.

Каким образом ты этот факт получаешь ?


 
Kolan ©   (2006-02-09 11:17) [2]

Таким образом по идее после её выполнения поток должен уничтожиться и освободить занимаемую им память.
А ты проверял. Он уничтожается?


 
isasa ©   (2006-02-09 11:22) [3]

А вот так?

procedure TForm1.StartMaket;
var Maket:TMaket;
begin
TTimer.Enable:=false;                           ///???????????????????????????
Maket:=TMaket.Create(true);
Maket.FreeOnTerminate:=true;
Maket.Resume;
TTimer.Enable:=true;                           ///???????????????????????????
end;


 
Ksenom   (2006-02-09 12:27) [4]

Digitman, Банально проверял. Beep ставил try...exept выделял... Логи вёл... Изначально я эту процедуру в основном vcl потоке вызывал и она нормально вс делает до конца.

Kolan, пробывал проверить. Через диспечер задачь смотре. Процес пошёл +1 поток, процес закончился поток-

Только вот получаеся что иногда не уничтожается. Я добавил принудительно Terminate... эффект тотже...

isasa, такой вариант я только что уже реализовал. Но вопрос в том что потоки не уничтожаются и память занимаемая программой потихоньку растёт...


 
Digitman ©   (2006-02-09 12:31) [5]

А вот так не пробовал ?

procedure TMaket.Execute;
begin
try
  Processing;
except
  MessageBox(0, "Грош цена моему факту !", "", mb_ok or mb_setforeground);
end;
end;


 
Defunct ©   (2006-02-09 12:39) [6]

Digitman ©   (09.02.06 12:31) [5]

А если циклится внутри, так ведь не покажет! :)


 
Digitman ©   (2006-02-09 12:41) [7]


> Defunct ©   (09.02.06 12:39) [6]


А брейкпойнт поставить на последнем END ?


 
Defunct ©   (2006-02-09 12:41) [8]

> Я добавил принудительно Terminate...

А тебя где-то в недрах Processing проверяется флажек Terminated? Иначе вызов Terminate - это все равно что в лужу плюнуть.


 
Ksenom   (2006-02-09 13:02) [9]

Digitman, я уже выше писал что конструкцию try...except использовал, более того и брэкпоинты и флаги... функция ошибку не даёт...

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


 
Digitman ©   (2006-02-09 13:10) [10]


> Ksenom   (09.02.06 13:02) [9]


Тогда показывай. что у тебя творится в теле Processing() ..


 
Ksenom   (2006-02-09 14:33) [11]

Digitman, смотри )


//Основная процедура проверки, обработки и сохранения
procedure TMaket.Processing;
 var MAPI_Session  :Cardinal;
     MesID         :array [0..512] of Char;
     Mes           :PMapiMessage;
     Base          :TADOQuery;
     MDT           :TDateTime;
begin
 if MapiLogon(Application.Handle,nil,nil,MAPI_LOGON_UI or MAPI_NEW_SESSION,
 0,@MAPI_Session)<>SUCCESS_SUCCESS
 then begin
   MapiLogOff(MAPI_Session,Application.Handle,0,0);
   Sleep(20000);
   if MapiLogon(Application.Handle,nil,nil,MAPI_LOGON_UI or MAPI_NEW_SESSION,
   0,@MAPI_Session)<>SUCCESS_SUCCESS
   then begin
   MapiLogOff(MAPI_Session,Application.Handle,0,0);
   Sleep(20000);
     if MapiLogon(Application.Handle,nil,nil,MAPI_LOGON_UI or MAPI_NEW_SESSION,
     0,@MAPI_Session)<>SUCCESS_SUCCESS
     then begin //Ошибка при подключении к почтовику
       MapiLogOff(MAPI_Session,Application.Handle,0,0);
       Notification(1,"");
       exit;
     end;
   end;
 end;

 Base:=TADOQuery.Create(nil);
 Base.ConnectionString:=Form1.BS;
 Base.SQL.Add("SELECT MAX(Dat) as Dat FROM ErrorLog WHERE PlantID="+Form1.PlantID+" AND Type=355");
 try
   Base.Open;
   MDT:=Base.FindField("Dat").AsDateTime;
   Base.Close;
 except  //ошибка работы Maket355logs
   Base.Close;
   Base.Free;
   MapiLogOff(MAPI_Session,Application.Handle,0,0);
   Notification(2,"");
   exit;
 end;

 while MAPIFindNext(MAPI_Session,0,0,MesID,0,0,MesID)=SUCCESS_SUCCESS
 do begin
   //Передача прочитанного MesID письма в Mes
   MAPIReadMail(MAPI_Session,0,MesID,MAPI_SUPPRESS_ATTACH,0,Mes);

   {1.Проверка письма на пригодность подате}
   case FitnessOnDate(MDT,Mes.lpszDateReceived) of
     0 : {Продолжить};//Новое
     1 : continue{проверить следующее};//Старое
     2 : begin//Ошибка
           Notification(3,Mes.lpszDateReceived);
           break;
         end;
   end;
       
   {2.Проверка письма на пригодность по шапке}
   if not FitnessOnCodeObject(Mes.lpszNoteText) then continue;{Письмо не макет, проверить следующее}
   
   {3.Онализ макета и занесение в базу}
   case Parsing(Mes.lpszNoteText) of
     0 : begin//Макет обработан удачно
           if    Logs("1",Mes.lpszDateReceived,MaketDate)
           then  Notification(0,Mes.lpszNoteText)
           else  Notification(2,"");
         end;
     1 : begin//Макет не коректен
           if    Logs("0",Mes.lpszDateReceived,"Макет не коректен")
           then  Notification(4,Mes.lpszNoteText)
           else  Notification(2,"");
         end;
     //Ошибка при сохранении данных
     2 : begin //PBR
           if    Logs("0",Mes.lpszDateReceived,"Ошибка PBR")
           then  Notification(5,Mes.lpszNoteText)
           else  Notification(2,"");
           break;
         end;
     3 : begin //TG
           if    Logs("0",Mes.lpszDateReceived,"Ошибка TG")
           then  Notification(6,Mes.lpszNoteText)
           else  Notification(2,"");
           break;
         end;
     4 : begin //Makets
           if    Logs("0",Mes.lpszDateReceived,"Ошибка Makets")
           then  Notification(7,Mes.lpszNoteText)
           else  Notification(2,"");
           break;
         end;
   end;
 end;
 Base.Free;
 MAPIFreeBuffer(Mes);
 MapiLogOff(MAPI_Session,Application.Handle,0,0);
end;


 
Digitman ©   (2006-02-09 14:46) [12]

Первое что бросается в глаза - где CoInitialize/CoUninitialize ?


 
Ksenom   (2006-02-09 14:54) [13]

Digitman, буду крайне признателе если ты меня просветишь для чего здесь это нужно.
В dll я их тспользовал, ибо без них у меня  ADODB не работало. Я где то читал, что основной vcl поток сам это делает при инициализации...


 
Digitman ©   (2006-02-09 14:58) [14]


> где то читал, что основной vcl поток сам это делает при
> инициализации


Правильно.
Но у тебя-то - дополнительный !
И DLL здесь ни при чем - там иная песня.
А в дополнительном потоке ты сам ответственен за инициализацию СОМ.


 
wal ©   (2006-02-09 14:59) [15]


> Я где то читал, что основной vcl поток сам это делает при
> инициализации...
Но эта процедура, по твоим словам, не в основном потоке выполняется


 
wal ©   (2006-02-09 15:01) [16]

Еще один крайне интересный момент:

> Base.ConnectionString:=Form1.BS;


 
Digitman ©   (2006-02-09 15:23) [17]

явный вызов CoInitialize/CoUninitialize обязателен в случае, если это ДЛЛ-проект ИЛИ если проект нигде не задействует юнит ComObj.

Это явно следует из исх.текста ComObj.


 
Ksenom   (2006-02-09 15:33) [18]

wal, перед старом потока я записываю в глобальную переменную BS:string строку подключения к базе.
Base.ConnectionString:=Form1.BS; а здесь я к ней обращаюь...


 
Digitman ©   (2006-02-09 15:39) [19]


> Ksenom   (09.02.06 15:33) [18]


> а здесь я к ней обращаюь


А если на этот момент в основном потоке по тем или иным причинам содержимое BS изменится ?
Или будет в ходе изменения в момент обращения к BS из доп.потока ?
Об этом не подумал ?


 
wal ©   (2006-02-09 15:54) [20]


> [18] Ksenom   (09.02.06 15:33)
Ну, во первых, не глобальная переменная, а поле/метод/свойство объекта. Или у тебя модуль называется Form1? Во вторых, операции со строками на уровне процессора далеко не атомарны и даже на одном процессоре возможен вариант, когда в одном потоке "еще не закончили писать", а в другом "уже прочитали некий полуфабрикат". Но если ты записываешь туда ТОЛЬКО перед стартом потока и больше нигде, а BS это действительно голобальная переменная, описанная в модуле Form1 или поле, но не метод и не свойство объекта Form1, тогда претензия снимается. Иначе все на потокобезопасность проверять, или "предохраняться" крит.секциями.
Ну и в третьих, вызови таки ComInitialize.

С уважением.


 
isasa ©   (2006-02-09 20:50) [21]

А есть ли здесь многопоточность?
По логике надо бы CoInitializeEx

MSDN. Platform SDK: COM
CoInitializeEx provides the same functionality as CoInitialize and also provides a parameter to explicitly specify the thread"s concurrency model. CoInitialize calls CoInitializeEx and specifies the concurrency model as single-thread apartment. Applications developed today should call CoInitializeEx rather than CoInitialize.



 
isasa ©   (2006-02-09 20:58) [22]

Попробуй в *.dpr файле

...
CoInitFlags:=COINIT_APARTMENTTHREADED;  // or COINIT_MULTITHREADED
Application.Initialize;
...



Страницы: 1 вся ветка

Текущий архив: 2006.03.12;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.05 c
3-1137869326
Alex222
2006-01-21 21:48
2006.03.12
Компилятор ругается на несовпадение типов.


15-1140253606
Yurc
2006-02-18 12:06
2006.03.12
Indy


15-1139842073
Хинт
2006-02-13 17:47
2006.03.12
Программа для сравнения файлов


15-1140051172
Ученик чародея
2006-02-16 03:52
2006.03.12
Какая тема научной работы была у Вирта?


2-1140519531
reboot
2006-02-21 13:58
2006.03.12
Запыхался. .. .. .. .