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

Вниз

Уважаемые Дельфисты - проблемма с потоками   Найти похожие ветки 

 
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;
Скачать: CL | DM;

Наверх




Память: 0.56 MB
Время: 0.023 c
1-29449
electronic
2004-01-30 18:16
2004.02.10
CD + запись в файл


14-29591
Jew_lo
2004-01-19 16:30
2004.02.10
Вот так мамаша


1-29455
ivankohut
2004-01-30 16:36
2004.02.10
Grid и Unicode


1-29396
Ivolg
2004-02-01 12:28
2004.02.10
Помемещение в трей


4-29667
Bopros
2003-12-04 19:50
2004.02.10
Помогите с GetNamedSecurityInfo