Форум: "Основная";
Текущий архив: 2004.02.10;
Скачать: [xml.tar.bz2];
ВнизУважаемые Дельфисты - проблемма с потоками Найти похожие ветки
← →
denisWW (2004-01-28 00:23) [0]Уважаемые Дельфисты - проблемма с потоками
всё начинается просто:
Type
TMapThread=class(TThread)
private
protected
Procedure Execute; override;
procedure DoTerminate; override;
public
end;
var
MapThread:TMapThread;
Const
MapThreadActive:Boolean=False;
implementation
Procedure TMapThread.DoTerminate;
Begin
MapThread.FreeOnTerminate:=True;
MapThreadActive:=False;
End;
Procedure TMapThread.Execute;
Begin With Form1 Do Begin
MapThreadActive:=True;
..........
здесь идёт кусок кода который может выполнятся достаточно долго .....
{поиск и работа с рисунками в цикле
существует в этом цикле и метод такой:
if Terminated Then Exit;
для быстрого выхода из цикла}
..........
End End;
Вызов процедуры возможен очень быстро и
я хочу тогда тормозить поток действующий и запускать его заново
текст такой
If MapThreadActive and (MapThread<>Nil) Then With MapThread Do Begin
Terminate;
WaitFor;
End;
MapThread:=TMapThread.Create(False);
и так по кругу
Проблемма такая через несколько быстрых циклов XP-начинает работать неправильно - но без явной ошибки
а вот Win98 даёт ошибку явно:
System error: Code 6
Неверный дескриптор
где зараза зарыта!!!????????
я тестировал
ощущения что перед Terminate;WaitFor; оператор With MapThread Do теряет указатель на поток :(
← →
denisWW (2004-01-28 00:37) [1]Вот такой Execute; уже вызывает ошибку
Procedure TMapThread.Execute;
Var
IniExp:TIniFile;
Begin With Form1 Do Try
MapThreadActive:=True;
IniExp:=TIniFile.Create(ShellTreeView.SelectedFolder.PathName+"\Default.ini");
Finally
IniExp.Free;
End End;
как видите я использую обьект ShellTreeView
← →
DenisWW (2004-01-28 00:53) [2]Сделал так и всёравно ошибка!!!!!
Procedure TMapThread.WWW;
Var IniExp:TIniFile;
Begin
IniExp:=TIniFile.Create(Form1.ShellTreeView.SelectedFolder.PathName+"\Default.ini");
IniExp.Free;
End;
Procedure TMapThread.Execute;
Begin With Form1 Do Try
MapThreadActive:=True;synchronize(WWW);
Finally
End End;
← →
DenisWW (2004-01-28 01:06) [3]кстати если удалить вызов ShellTreeView.SelectedFolder.PathName то всё работает- правда путь несуществующий
← →
sniknik (2004-01-28 01:10) [4]> как видите я использую обьект ShellTreeView
визуальный компонент, шспользующий VCL? ну это ты зря в потоке. не threadsafe компонент.
в потоке вообще не должно фигурировать форм, компонентов с этих форм, переменных... и т.д.
и если используеш WaitFor (вызов и заверщение не показано но могу предположить) делай FreeOnTerminate:= false; и сам его после вызова освобождай, а то действительно возможен вариант, он завершится и освободится до вызова WaitFor(и тогда на ней ошибка). или не используй WaitFor.
← →
DenisWW (2004-01-28 08:59) [5]Если заменить текст
If MapThreadActive and (MapThread<>Nil) Then With MapThread Do Begin
Terminate;
WaitFor;
End;
MapThread:=TMapThread.Create(False);
на
If MapThreadActive and (MapThread<>Nil) Then With MapThread Do Begin
Suspend;
End;
MapThread:=TMapThread.Create(False);
то всё работает !!!!!! вроде:)
Но вы понимаете , что поток ставится на паузу и существует в памяти, а мне нужно его удалить
соответственно вопрос:
Как из основного потока после вызова метода Terminate;
дождаться завершения доп. потока и освободить память
← →
DenisWW (2004-01-28 09:03) [6]А также реально вычислить - закончился поток или в работе?
← →
pasha_golub (2004-01-28 09:28) [7]Все операции с VCL в коде потока желательно оформлять через Synchronize
← →
Dred2k (2004-01-28 10:05) [8]Полезно делать так:
Terminate;
if(not Suspended) then
WaitFor;
Причем это можно прямо в деструктор помещать, а потом просто поток разрушать через Free. Авторазрушением не пользуюсь.
← →
DenisWW (2004-01-28 12:18) [9]Так я не хочу его засуспендить
я хочу подать сигнал в поток , что бы он как можно быстрее завершил себя и дождавшись этого запустить новую версию потока
соответсвенно правильно понимать :
1) Запущен ли поток(или он отработал и закрылся)
2) Если поток работает , закрыть его, подождать когда он закроется и запустить снова
Такое моё понимание потоков
← →
Sandman25 (2004-01-28 12:22) [10]Procedure TMapThread.Execute;
Begin With Form1 Do Try
MapThreadActive:=True;synchronize(WWW);
Finally
End End;
Выделенное жирным - тоже не thread-safe.
Лучше передавайте имя файла в конструкторе Вашего TThread.
← →
DenisWW (2004-01-28 12:29) [11]Я уже давно так сделал
и всё работает только если я в конце потоку делаю Suspend;
а если хочу его закрыть и выждать закрытие WaitFor;
то глюки идууууут
← →
Romkin (2004-01-28 12:32) [12]Намекаю: http://www.schevchenko.net.ru/ Супермаркет. Моделирование его работы потоками. Из Рихтера. Там все должно быть, и стартирование, и терминирование...
← →
Polevi (2004-01-28 12:50) [13]hint
код поточной ф-ии не забывавай оборачивать в try except, иначе будет бяка
← →
DenisWW (2004-01-28 12:53) [14]Ну есть мысль пользоваться одним потоком и просто его начинать с начало (с новыми парамметрами ) но это уже дело принципа
← →
Digitman (2004-01-28 13:05) [15]
> но это уже дело принципа
это дело далеко не принципа, а понимания преимуществ и недостатков такого подхода в конкретной среде и задаче
← →
panov (2004-01-28 13:14) [16]1. Поток создается с FreeOnTerminate := False
2. В основном коде:
MyThread.Terminate;
MyThread.WaitFor;
3. Никаких Suspend в потоке (в данной задаче) не нужно.
4. Если поток находится в спящем состоянии, то необходимо выполнить
MyThread.Terminate;
MyThread.Resume;
MyThread.WaitFor;
← →
DenisWW (2004-01-28 13:34) [17]
> panov © (28.01.04 13:14) [16]
> 1. Поток создается с FreeOnTerminate := False
> 2. В основном коде:
> MyThread.Terminate;
> MyThread.WaitFor;
>
> 3. Никаких Suspend в потоке (в данной задаче) не нужно.
>
> 4. Если поток находится в спящем состоянии, то необходимо
> выполнить
>
> MyThread.Terminate;
> MyThread.Resume;
> MyThread.WaitFor;
я это и делаю
происходит трабл как я писал выше
Проблемма такая через несколько быстрых циклов XP-начинает работать неправильно - но без явной ошибки
а вот Win98 даёт ошибку явно:
System error: Code 6
Неверный дескриптор
← →
DenisWW (2004-01-28 13:37) [18]Тоесть попытка послать тормоз потоку и подаждать пока он завершится и тутже вызвать новую версию потока
If MapThreadActive and (MapThread<>Nil) Then With MapThread Do Begin
Terminate;
WaitFor;
End;
MapThread:=TMapThread.Create(False);
при достаточно быстром повторе даёт сбой
← →
panov (2004-01-28 13:39) [19]при достаточно быстром повторе даёт сбой
При каком повторе?
WaitFor означает, что следующий оператор у тебя не выполнится, пока не завершится поток.
Кстати, забыл, что поток тебе нужно уничтожить вручуню. Т.е. после WaitFor нужно выполнить MyThread.Free;
← →
DenisWW (2004-01-28 13:40) [20]Повтор я имею ввиду - скорость повтора при удерживании клавиши
← →
DenisWW (2004-01-28 13:41) [21]я уничтожаю поток таким образом
Procedure TMapThread.DoTerminate;
Begin
MapThread.FreeOnTerminate:=True;
MapThreadActive:=False;
End;
← →
DenisWW (2004-01-28 13:44) [22]procedure TForm1.ShellTreeView1Change(Sender: TObject; Node: TTreeNode);
begin
If MapThreadActive and (MapThread<>Nil) Then With MapThread Do Begin
Terminate;
WaitFor;
End;
MapThread:=TMapThread.Create(False);
end;
Поток вызывается при смене директории в обьекте ShellTreeView папка Samples
← →
panov (2004-01-28 14:02) [23]Что такое DoTerminate и что такое MapThreadActive ?
Если MapThreadActive - глобальная переменная, то обрати внимание на работу с этой переменной.
← →
csr_ (2004-01-28 14:05) [24]Ты потоки не синхронизируешь - от сюда глюки !!!
← →
DenisWW (2004-01-28 14:30) [25]
> csr_ (28.01.04 14:05) [24]
> Ты потоки не синхронизируешь - от сюда глюки !!!
обьясни
← →
DenisWW (2004-01-28 14:48) [26]
> Что такое DoTerminate и что такое MapThreadActive ?
> Если MapThreadActive - глобальная переменная, то обрати
> внимание на работу с этой переменной.
DoTerminate это:
Generates an OnTerminate event.
procedure DoTerminate; virtual;
Description
DoTerminate calls the OnTerminate event handler, but does not terminate the thread.
По русски :
Процедура которая выполняется когда поток закрывается
________________________________________________________
MapThreadActive булевая глобальная переменная которая которая в начале execute устанавливается в True , а в конце OnTerminate в False - я думаю , что это мне поможет понять запущен ли поток
← →
DenisWW (2004-01-28 14:58) [27]стынет вопрос то!!!
← →
sniknik (2004-01-28 15:36) [28]отвечающим то надоело. ответы были проигнорированы.
(ну ладно я кратко, и может непонятно, написал но уж Панов вообше все по полочкам разложил. а толку?)
← →
AKul (2004-01-28 15:45) [29]to denisWW © :
Проблема в том, что FreeOnTerminate:=true выполняется в DoTerminate!
Если взглянуть на код TThread.ThreadPorc (это то, что Windows вызовет после CreateThread):
try
Thread.Execute;
finally
FreeThread := Thread.FFreeOnTerminate;// смотрим сюда
Result := Thread.FReturnValue;
Thread.FFinished := True;
Thread.DoTerminate; // потом сюда
if FreeThread then Thread.Free; // и наконец сюда
EndThread(Result);
end;
Думаю теперь стало ясно?
Так сделано потому, что уже нет возможности возобновить выполнение метода Execute (он завершился)!
← →
DenisWW (2004-01-28 20:29) [30]Поправка существенная но ....
к сожалению она не исправила ничего
← →
DenisWW (2004-01-28 20:51) [31]Почему этот текст правильный
If MapThreadActive and (MapThread<>Nil) Then With MapThread Do Begin
Terminate;
WaitFor;
MapThread.Free;
End;
MapThread:=TMapThread.Create(True);
MapThread.Resume;
а этот неправильный ???????????
If MapThreadActive and (MapThread<>Nil) Then With MapThread Do Begin
Terminate;
WaitFor;
End;
MapThread:=TMapThread.Create(True);
MapThread.FreeOnTerminate:=True;
MapThread.Resume;
← →
panov (2004-01-28 21:44) [32]>DenisWW © (28.01.04 20:51) [31]
Потому что поток у тебя не уничтожается во втором случае...
← →
sniknik (2004-01-28 22:00) [33]panov © (28.01.04 21:44) [32]
поправка.
он же его(этот код) гонит постоянно как бы в цикле (гдето писал о нажатии клавиши, и удержании)
наоборот он во втором случае уничтожится (иногда) раньше чем вызов WaitFor произойдет.
перепиши код в нормальном виде яснее будет (вот за это нелюблю With)
второй "нормализованный" вариант
> а этот неправильный ???????????
begin //типа кусок кейпрессед
If MapThreadActive Then Begin
MapThread.Terminate; //на завершение и уничтожение!!!! см. FreeOnTerminate
MapThread.WaitFor; //обращение к возможно успевшему самоуничтожится обьекту MapThread !!!ошибка!!!ошибка!!!ошибка!!!
End;
MapThread:=TMapThread.Create(True); //начинается отсюда
MapThread.FreeOnTerminate:=True; //самоуничтожение!!!
MapThread.Resume; //запустили
MapThreadActive:= true;
end.
← →
panov (2004-01-28 22:17) [34]>sniknik © (28.01.04 22:00) [33]
Сорри, но если FreeOnTerminate=True, то WaitFor не сработает...
← →
sniknik (2004-01-28 22:35) [35]panov © (28.01.04 22:17) [34]
а обрашение к методу будет? думаю да. а там нет ничего, уже.
← →
AKul (2004-01-29 09:35) [36]
> DenisWW © (28.01.04 20:29) [30]
> Поправка существенная но ....
> к сожалению она не исправила ничего
Освобождайте поток сами (FreeOnTerminate:=false), после вызова WaitFor.
Зачем Вам в цикле постоянно создавать и завершать поток?
Логичнее было б, если бы поток 1 раз создавался, а цикл крутился внутри его (да и к тому же не будет попросту расходоваться процессорное время). А управлять циклом внутри этого потока Вы всегда сможете из любого другого потока.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2004.02.10;
Скачать: [xml.tar.bz2];
Память: 0.53 MB
Время: 0.008 c