Перейти из форума на сайт.

НовостиФайловые архивы
ПоискАктивные темыТоп лист
ПравилаКто в on-line?
Вход Забыли пароль? Первый раз на этом сайте? Регистрация
Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » ошибка в уничтожении потока Delphi+Thread+TerminateThread

Модерирует : ShIvADeSt

 Версия для печати • ПодписатьсяДобавить в закладки
Страницы: 1 2

Открыть новую тему     Написать ответ в эту тему

Delphi6



BANNED
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Вот сейчас сменил код fIdHTTP.Free на FreeAndNil(fIdHTTP) ошибок при тестировании не было (проводил два раза), вот только на 220 и 290 запуске/уничтожении потоки подвисли. Так что надо еще поработать. Мои подозрения таковы, потоки подвисают и не могут быть убиты. Сейчас еще раз пересмотрю код вызова и уничтожения потоков, на наличие ошибок.
 
FireZone
Вот сколько времени программирую а о конструкции  
  on E: Exception do бла бла
не слышал, довольно удобно, сейчас сделаю, посмотрим что у нас там будет. А как я уже говорил мне надо еще раз удостовериться что потоки именно повисают Я пробовал отследить в цикле количество рабочих (assigned) потоков и оно при ситуации "подвиса" равно было 15, как и запланировано. Получается что все таки потоки подвешены

Всего записей: 2631 | Зарегистр. 06-07-2004 | Отправлено: 08:35 02-06-2006 | Исправлено: Delphi6, 08:41 02-06-2006
OdesitVadim



Advanced Member
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору
Delphi6
О логгировании. Наиболее удобным (для меня по крайней мере) есть процедурка
OutputDebugString(msg:PAnsiChar); Для использования нужно подключить модуль Windows (он обычно уже подключен). Если запускаем с под Делфи, то сообщения можно подсмотреть в окошке Event Log. Там они будут предварятся префиксом ODS. Когда испытываеш на чужой машине, то качаеш DebugView (сам exe - 236k) отсюдова http://www.sysinternals.com/utilities/debugview.html
Он выводит все эти сообщения. Он также поможет, если пишеш сервисы или другие гадости.

----------
Press any key to continue or any other key to exit
Пишите так, чтобы не было стыдно за нобелевскую премию.

Всего записей: 1568 | Зарегистр. 19-09-2003 | Отправлено: 11:41 02-06-2006
FireZone

Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Delphi6
Еще небольшая рекомендация
Код:
procedure TProxyChecker.Execute;  
  var  
    PCT: TProxyCheckerThread;  
    StartTime: Integer;  
    timePass: Integer;  
begin  
  //Prepare thread and execute to recieve result from URL  
  PCT := TProxyCheckerThread.Create(fUrl, fServer, fPort);  
  try //для гарантии уничтожения PCT в случае исключений
    StartTime := GetTickCount;  
    timePass := 0;  
    //Work until time will finish and result from page will be recieved  
    while (timePass < fTimeout) and (not PCT.GetResult) do begin  
      sleep(100); // для усыпления потока на 100 мс при каждом проходе, чтобы не загружать процессор холостым циклом
      timePass := GetTickCount-StartTime;  
      //Wait for result or timeout  
    end;  
    //Checking if result exist and analyze it  
    if PCT.GetResult then begin  
      fProxyLatency := timePass;  
      AnalyzeResult(PCT.GetResultString);  
    end else  
      fProxyType := ptBad;  
    //Remove thread, even in case if it still running  
    //First of all of cause terminate any connection  
    PCT.TerminateConnection;  
    PCT.WaitFor;  
  finally
    PCT.Free;  
  end;
  fResult := True;  
end;  
Ну и тело всей процедуры возьми так же в блок try except end и пиши исключения в лог по тому же принципу. Полезно так же в лог записывать входные параметры и результаты, чтобы отследить, при каких условиях возникает ошибка. А FreeAndNil(fIdHTTP) перенеси всё же в деструктор. Это для хорошего стиля, чтобы самому же потом не путаться, где что уничтожается.

Всего записей: 293 | Зарегистр. 28-01-2004 | Отправлено: 13:01 02-06-2006
Delphi6



BANNED
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

Цитата:
sleep(100); // для усыпления потока на 100 мс при каждом проходе, чтобы не загружать процессор холостым циклом  

Дельный совет, зачем проверять так часто если таймаут будет минимум 10 сек, а проверять даже можно каждую секунду, так как от этого почти ничего не меняется для проверки а зато понижается загрузка процессора. Спасибо
 

Цитата:
качаешь DebugView

Сегодня запланировано у меня длительное тестирование при разных ситуациях. Программа думаю ценная так как позволяет просматривать состояние переменных (если их логировать) именно в потоках, чего стандартными способами добиться нельзя. Кстати ведение логов думаю будет рационально до того момента как программа из Альфа и Бета версий перейдет в Финальную.
 
А как вы поступаете с вашими проектами? Ведете ли логи, если да то как потом получаете их от ваших пользователей?
 
OdesitVadim
Ваша прога супер, удивительно но кажется ошибка в коде запуска одновременных потоков. После длительных запусков, алгоритму кажется что поток еще работает а на самом деле он уже убит, в логах видно! Так что начал пересматривать код.
Все замечания по коду приняты и уже внесены, спасибо
п.с. Скоро выложу результаты поисков
 
Выше указанный текст не совсем правда, вот что получил после теста:
 

Код:
procedure TProxyChecker.Execute;
  var
    PCT: TProxyCheckerThread;
    StartTime: Integer;
    timePass: Integer;
 
    i: integer;
begin
  i := Random(1000000);
  try
    OutputDebugString(pChar('Information: #'+ IntToStr(fThreadIndex) +'('+ IntToStr(i) + ') Start Working!'));
    //Prepare thread and execute to recieve result from URL
    PCT := TProxyCheckerThread.Create(fUrl, fServer, fPort);
    StartTime := GetTickCount;
    timePass := 0;
    //Work until time will finish and result from page will be recieved
    while (timePass < fTimeout) and (not PCT.GetResult) do begin
      Sleep(100);
      timePass := GetTickCount-StartTime;
      //Wait for result or timeout
    end;
    OutputDebugString(pChar('Information: #'+ IntToStr(fThreadIndex) +'('+ IntToStr(i) + ') Timrout!'));    
    //Checking if result exist and analyze it
    if PCT.GetResult then begin
      fProxyLatency := timePass;
      OutputDebugString(pChar('Information: #'+ IntToStr(fThreadIndex) +'('+ IntToStr(i) + ') Before Analyze!'));
      AnalyzeResult(PCT.GetResultString);
      OutputDebugString(pChar('Information: #'+ IntToStr(fThreadIndex) +'('+ IntToStr(i) + ') After Analyze!'));      
    end else
      fProxyType := ptBad;
    OutputDebugString(pChar('Information: #'+ IntToStr(fThreadIndex) +'('+ IntToStr(i) + ') Start Term!'));
    //Terminate and wait until thread will finish its working (may cause hang on)
    PCT.TerminateConnection;
    PCT.WaitFor;
  finally
    FreeAndNil(PCT);
  end;
  OutputDebugString(pChar('Information: #'+ IntToStr(fThreadIndex) +'('+ IntToStr(i) + ') Finish Term!'));
  fResult := True;
end;

 
Ошибка была там где ее ни кто не ждал Теперь идет анализ данной процедуры.
 
00000426    211.00106812    [2588] Information: #3(95638) Finish Term!    
...REMOVED...
00000427    211.00234985    [2588] Information: #2(458778) Start Working!    
00000428    211.00700378    [2588] Information: #0(302291) Start Working!    
00000429    211.00834656    [2588] Information: #1(371939) Start Working!    
00000430    211.01031494    [2588] Information: #3(644890) Start Working!    
00000431    211.23666382    [2588] Information: #4(736844) Timrout!    
00000432    211.23706055    [2588] Information: #4(736844) Start Term!    
00000433    211.23727417    [2588] Information: #4(736844) Finish Term!    
00000434    211.24046326    [2588] Information: #4(204749) Start Working!    
00000435    211.63813782    [2588] Information: #3(644890) Timrout!    
00000436    211.63964844    [2588] Information: #3(644890) Before Analyze!
00000437    221.07006836    [2588] Information: #2(458778) Timrout!    
00000438    221.07040405    [2588] Information: #2(458778) Start Term!    
00000439    221.07049561    [2588] Information: #0(302291) Timrout!    
00000440    221.07055664    [2588] Information: #1(371939) Timrout!    
00000441    221.07061768    [2588] Information: #0(302291) Start Term!    
00000442    221.07290649    [2588] Information: #1(371939) Start Term!
...REMOVED...
00000514    261.44900513    [2588] Information: #4(316211) Start Term!    
00000515    261.45089722    [2588] Information: #4(316211) Finish Term!    
00000516    261.45382690    [2588] Information: #4(261328) Start Working!    
...REMOVED...

Всего записей: 2631 | Зарегистр. 06-07-2004 | Отправлено: 05:28 03-06-2006 | Исправлено: Delphi6, 10:56 03-06-2006
OdesitVadim



Advanced Member
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору

Цитата:
А как вы поступаете с вашими проектами? Ведете ли логи, если да то как потом получаете их от ваших пользователей?

Я в тексте программы ставлю вызов процедурки типа

Код:
 
procedure debug(s:string);
begin
{$ifdef debug}
  Outputdebugstring(pAnsiChar(s));
{$else}
  //а здесь запись в файл по необходимости.
{$endif}
end;
 

Всего записей: 1568 | Зарегистр. 19-09-2003 | Отправлено: 13:27 03-06-2006
Delphi6



BANNED
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Ну думаю вопрос можно считать почти закрытым. Сейчас провожу очень большой тест длительностью в 3 часа минимум, после него можно будет с точностью говорить насколько все правильно выполнено.
 
Хочу подвести итоги, дабы второй пользователь на данном форуме не наступил на теже грабли. Главное надо пользоваться процедурой FreeAndNil() вместо стандартного Free. Я лично теперь для всех объектов его буду использовать, для подстраховки
 
Второе, нужно все подозрительные части кода ставить в try except и обязательно все подозрительные части где происходит создание объекта в try finally что бы быть уверенным что он удалиться даже при случае ошибки.
 
В третьих посоветую многим воспользоваться программой которую мне предложил OdesitVadim очень сильная вещь, особенно если тестирование будет производиться уже с готовым EXE-шником да и на другом компьютере. Превосходство этой программы от обыкновенной записи в файл следующие, вы в реал таиме видите все, можно не беспокоиться что файл после записи будет закрыт правильно (если открывать и тут же закрывать файл, понизиться производительность программы).
 
Также важно то что надо избегать использования TerminateThread так как при этом большие потери памяти. А зачищаться эта память будет только после отключения программы что ни есть хорошо, если в программе происходит очень много (больше 1000) аварийных уничтожений.
 
Ну и на последок, хочу всех поблагодарить, без вашей помощи я бы не справился, я многому новому научился в этой ветке.
 
п.с. Ошибка была в теле AnalyzeResult, при некоторых ситуациях код обращался к не существующему элементу массива (динамического).

Всего записей: 2631 | Зарегистр. 06-07-2004 | Отправлено: 07:14 04-06-2006 | Исправлено: Delphi6, 07:45 04-06-2006
FireZone

Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

Цитата:
FreeAndNil() вместо стандартного Free
Для красоты стиля всё же лучше использовать Free и только в специфических случаях FreeAndNil. А именно тогда, когда какие-то участки кода ориентируются на существование объекта по ненулевому значению указателя.
Цитата:
Второе, нужно все подозрительные части кода ставить в try except
И не забывать правильно обрабатывать исключения, иначе можно от самого себя скрыть важную ошибку и долго искать глюки в коде и утечки памяти и ресурсов. Например, самой глупой опрометчивостью будет намеренно прятать ошибки Access Violation в блоки try ... except end.
Цитата:
В третьих посоветую многим воспользоваться программой которую мне предложил OdesitVadim
И я попробую.
Цитата:
можно не беспокоиться что файл после записи будет закрыт правильно

Чтобы не беспокоитсья, используем опять же try-finally:
Код:
reset(f);
try
  ...
finally
  closefile(f)
end

Цитата:
если открывать и тут же закрывать файл, понизиться производительность программы
Я бы усомнился, что производительность будет ниже, чем с OutputDebugString
Цитата:
Также важно то что надо избегать использования TerminateThread так как при этом большие потери памяти.
Потерь памяти не будет, если пользовательская функция потока сама эту память не выделяет (явно или косвенно) и не освобождает. А вот на приведённую в этом топике цитату из описалова функции TerminateThread касательно использования в потоке функций ядра обратить внимание стоит. В общем, проблема несколько глубже, чем потерянная память.
Цитата:
п.с. Ошибка была в теле AnalyzeResult, при некоторых ситуациях код обращался к не существующему элементу массива (динамического).
Классический AccessViolation

Всего записей: 293 | Зарегистр. 28-01-2004 | Отправлено: 16:39 04-06-2006
Delphi6



BANNED
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
FireZone
Очень хорошие и интересные коменты, со всем согласен, кроме FreeAndNil() IMHO лучше всегда им пользоваться
 
А на счет try except вы правильно подметили, возможно случайно запутать самого себя. Так что лучше все легировать в файл и OutputDebugString.
 
Вчерашнее тестировании показало себя как нельзя лучше. Все удачно прошел с 3000 потоками Так что объявляю тему закрытой
 
Всем спасибо

Всего записей: 2631 | Зарегистр. 06-07-2004 | Отправлено: 03:04 05-06-2006
vserd

Silver Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

Цитата:
Главное надо пользоваться процедурой FreeAndNil() вместо стандартного Free.

Главное это нужно понимать что делая объекту MyVar.Free мы освобождаем память, указатель на которую храниться в переменной MyVar, но не обнуляем указатель MyVar(значение переменной MyVar). А если эта переменная находится в области видимости отличной от локальной, и идет проверка на Nil / not NIL, тогда нужно писать два предложения вместо одного.
MyVar.Free;
MyVar := Nil;
 
А включать дополнительный модуль ради одной этой функции, является излишеством.
 
Для понимания посмотри на код FreeAndNil:
 
procedure FreeAndNil(var Obj);
var
  P: TObject;
begin
  P := TObject(Obj);
  TObject(Obj) := nil;  // clear the reference before destroying the object
  P.Free;
end;
 
Что касаемо OutputDebugString. Не забывай что для пользования этой функцией тебе нужно будет иметь соответствующие права доступа (Администратор по умолчанию, для других пользователей настраевается). А в корпоративной среде все сидят под ограниченной учеткой и таких прав у них обычно нет. Вывод в файл обычно не зависит от таких прав и пользователю гораздо легче объяснить по телефону откуда скопировать файл лога и как его отослать по почте разарботчику чем как сграбить данные выводимые по ODS.

Всего записей: 2065 | Зарегистр. 08-05-2002 | Отправлено: 13:25 05-06-2006
DavidMoore

Newbie
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Господа программисты подскажите новечку плис.
я только начал разбираться с потоками и вот какая штука возникла:
у меня есть форма с скроллбаром, 2 потока, первый двигает позицию влево, второй соответственно вправо. При любых приоритетах почему то выйгрывает первый поток. так и должно быть? или я чтото упустил?
бррр... извиняюсь задаю тупые вопросы изза своей невнимательности. всё ок.

Всего записей: 2 | Зарегистр. 26-06-2007 | Отправлено: 12:51 09-07-2008 | Исправлено: DavidMoore, 13:20 09-07-2008
OdesitVadim



Advanced Member
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору
а первый поток первым запускается? может он банально не даёт второму передвигать?
Как синхронизация доступа к скроллбару осуществляется?

----------
Press any key to continue or any other key to exit
Пишите так, чтобы не было стыдно за нобелевскую премию.

Всего записей: 1568 | Зарегистр. 19-09-2003 | Отправлено: 13:20 09-07-2008
DavidMoore

Newbie
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
да нет всё оказалось гораздо проще  
я забыл второй поток запустить в цикле он передвинул 1 раз и закрылся

Всего записей: 2 | Зарегистр. 26-06-2007 | Отправлено: 13:24 09-07-2008
VitalijUA

Newbie
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
В продолжении этой темы.  
У меня такая ситуация, нужно создать и удалить поток (всего их в последствии будет 3 различных) но так что бы при его повторном создании он не возвращался в ту точку в Execute где он был остановлен или удален.
Для примера создал небольшую программу для тестирования
В ней я поочередно меняю различного цвета image
type
  TP1 = class(TThread)
 protected
    procedure Execute; override;
    procedure Paint1;
  end;
........
procedure TP1.Execute;
begin
  { Place thread code here }
  i1:=0;   //i1: byte;
  x1:=0;  //x1: integer;
  y1:=0;  //y1: intrger;
  repeat
    sleep(250);
    if I1=16 then I1:=0;
    Synchronize(Paint1);
    sleep(1000);
    x1:=5;
    y1:=0;
    i1:=1;
    Synchronize(Paint1);
    sleep(1000);
    x1:=5;
    y1:=0;
    i1:=2;
    Synchronize(Paint1);
     .....//этот цикл может продолжаться очень долго, до нескольких минут
   Synchronize(Paint1);
    sleep(1000);
    x1:=30;
    y1:=15;
    i1:=13;
    Synchronize(Paint1);
    sleep(1000);
    x1:=0;
    y1:=0;
    inc(i1);
  until Terminated;
end;
 
procedure TP1.Paint1;
begin
Form1.Label1.Caption:=IntToStr(I1)+' | x1:'+IntToStr(x1)+'  y1:'+IntToStr(y1);
  Form1.ImgList.Draw(Form1.PaintBox1.Canvas,x1,y1,i1);
end;
 
Для создания потока использую
  if P1=nil then
  begin
    P1:=TP1.Create(True);
    P1.Priority:=tpNormal;
    P1.FreeOnTerminate:=False; //false для удаления в "ручную"  
    P1.Resume;
  end;
 
Для удаления
  if P1<>nil then
  begin
    P1.Suspend;
    P1.Terminate;
    P1.FreeInstance; //при Free не уничтожается
    P1:=nil;
   end;
так как один цикл в процедуре Execute может длится очень долго, с различными sleep по длительности и циклами while (в примере это не показанно) то автоматическое завершение при FreeOnTerminate:=true отпалает, программа приэтом подвисает т.е. ждет окончания цикла repeat. мне нужно чтобы поток Р1 завершался немедленно в любой момент времени, а при его повторном создании он начинался с начала Execute.
Удаление с помощью  
P1.Suspend;
P1.Terminate; //или TerminateTread(P1.Handle,0);
FreeAndNil(P1); // не удаляет поток после этого продолжает работать пока недостигнет конца цикла.
Я почти добился этого но, возникают ситуации когда много раз удаляешь и создаешь поток Р1 он продолжает работать.
Еще такой нюанс, что программа долна будет работать на Win millenium, но для начала нужно разобратся на ХР.
Жду советов...

Всего записей: 15 | Зарегистр. 17-03-2009 | Отправлено: 17:46 02-07-2009
ShIvADeSt



Moderator
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
VitalijUA
Фигней не майся, а запускай поток с параметрами. В зависимости от параметров делай нужные действия и после отработки завершайся. Примерно так

Код:
 
type
  TP1 = class(TThread)
 public
    MyParam=byte;
 protected
    procedure Execute; override;
    procedure Paint1;
  end;
 
 
  Execute..
  case MyParam of
   1....
   2....
   3....
  end;
 
  begin
    P1:=TP1.Create(True);
    P1.MyParam:=1 (2, 3);
    P1.Priority:=tpNormal;    
 
 

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

----------
И создал Бог женщину... Существо получилось злобное, но забавное...

Всего записей: 3956 | Зарегистр. 29-07-2003 | Отправлено: 01:57 03-07-2009
VitalijUA

Newbie
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

Цитата:
Фигней не майся, а запускай поток с параметрами. В зависимости от параметров делай нужные действия и после отработки завершайся. Примерно так  

 
Это было для примера а в реальной программе там много различных циклов и проверок
Будет выглядить так:

Код:
 
TP1.Execute;
  repeat  
    sleep(5000); //от 3000 до 180000
    if ...  
    while...  
    sleep( );
     if ...  
    while...  
    sleep( );
    while ...sleep(250);
    z:=k+c-d;
    while ...sleep(500);
    if...;
    a:=b+c-d;
    if....begin while... if... while.. end;
    ......  
    buff[5]:=buff[4]-buff[j]+buff[i]
    while... ;
    sleep( );
    while ..if ..sleep(30000);
    inc();  
  until Terminated;  
end;  
 

 
Надеюсь так будет нагляднее, полный текст невыкладываю.  
И параметры здесь не помогут. там обработка масивов и глобальных переменных.

Всего записей: 15 | Зарегистр. 17-03-2009 | Отправлено: 18:25 03-07-2009
delover

Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
VitalijUA
А sleepEx можно использовать, или задержки точно вымеренные? У меня TerminateThread всегда проходит если хендл актуален. Но веть это функция! По моему приблизительно так - if TerminateThread then Thrd.Free.

Всего записей: 1395 | Зарегистр. 25-06-2007 | Отправлено: 18:27 06-07-2009
Rudia



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
По поводу завершения потоков.
Нужно использовать метод TThread waitfor после вызова terminate - он ждет, пока произойдет выход из метода Execute (для этого метод еxecute должен завершаться по  установлению terminated в true). А уже потом можно вызывать free.
Насчет FreeAndNil - это то же самое, что вызвать метод free и присвоить значение объекту nil.
А метод free - это вызов для объекта destroy c проверкой, не является ли ccылка на объект nil.
Вот если вызвать 2 раза destroy для одного объекта - дело закончится критической ошибкой.

Всего записей: 324 | Зарегистр. 13-09-2006 | Отправлено: 17:51 13-07-2009 | Исправлено: Rudia, 17:51 13-07-2009
VitalijUA

Newbie
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

Цитата:
Нужно использовать метод TThread waitfor после вызова terminate - он ждет, пока произойдет выход из метода Execute (для этого метод еxecute должен завершаться по  установлению terminated в true).

Waitfor мне не подойдет так как мне нужно НЕМЕДЛЕННОЕ завершение потока а не ждать пока процедура Execute  (т.е. цикл внутри ее) отработает, она  может никогда не завершиться и ожидать бесконечно!
Например там есть такие условия как:

Код:
while buff[3]<>0 sleep(500);
...
sleep(50000) //от 1000 до 180000мс могут быть задержки
 

Всего записей: 15 | Зарегистр. 17-03-2009 | Отправлено: 21:03 13-07-2009
ShIvADeSt



Moderator
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
VitalijUA
Почитал я тут дельфийский хелп по тридам, в общем там ни один из методом не дает 100% завершения потока. Так что мое мнение - завершай принудительно при помощи TerminateThread. Почитай хелп, что передавать и когда надо чтобы трид умер - убивай его этой функцией. Другого пути нет, так как (выдержка из хелпа)
 
Terminate sets the thread’s Terminated property to True, signaling that the thread should be terminated as soon as possible. Unlike the Windows API TerminateThread, which forces the thread to terminate immediately, the Terminate method merely requests that the thread terminate.

----------
И создал Бог женщину... Существо получилось злобное, но забавное...

Всего записей: 3956 | Зарегистр. 29-07-2003 | Отправлено: 03:07 14-07-2009
MrZeRo



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
VitalijUA
А разве нельзя вместо Sleep() использовать WaitForSingleObject() ? Во-первых, это менее ресурсоемкая операция (по моим наблюдениям, не претендующим на абсолютную истину), чем Sleep, во-вторых, она решает проблему прерывания потока, если использовать, например, Event или какой-нибудь другой объект (в вашем конкретном случае).

----------
... не это главное ...

Всего записей: 832 | Зарегистр. 30-01-2002 | Отправлено: 16:26 15-07-2009
Открыть новую тему     Написать ответ в эту тему

Страницы: 1 2

Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » ошибка в уничтожении потока Delphi+Thread+TerminateThread


Реклама на форуме Ru.Board.

Powered by Ikonboard "v2.1.7b" © 2000 Ikonboard.com
Modified by Ru.B0ard
© Ru.B0ard 2000-2025

BitCoin: 1NGG1chHtUvrtEqjeerQCKDMUi6S6CG4iC

Рейтинг.ru