Форум: "Основная";
Текущий архив: 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]А есть ли здесь многопоточность?
По логике надо бы CoInitializeExMSDN. 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.012 c