Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2006.03.12;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.52 MB
Время: 0.017 c
1-1139472708
DimaBr
2006-02-09 11:11
2006.03.12
Список компонентов


2-1140305836
Дмитрий_177
2006-02-19 02:37
2006.03.12
Переменные в моей функции


2-1141033977
Azeem
2006-02-27 12:52
2006.03.12
Буфер обмена


15-1140309906
Ученик чародея
2006-02-19 03:45
2006.03.12
Провал российского образования на международном тестировании.


2-1140710609
mozgan
2006-02-23 19:03
2006.03.12
ВСЕХ КОДЕРОВ С 23 ФЕВРАЛЯ !!!!!!!





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский