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

Вниз

THREADS !!!   Найти похожие ветки 

 
Evgeniy_S   (2001-11-28 16:13) [0]

блин, я уже запарился :(( помогите плиз разобраться с такой фигней (можно сказать чисто спортивный интерес, самое интересное, что в одной проге это работает, а при попытке повторения этого дела в других прогах отказывается! )

есть такое описание :
const
wm_stop_thread = wm_user + 2;

type
Thread = class (TThread)
protected
procedure execute;override;
procedure stop (var Msg : TMessage); message wm_stop_thread;
procedure UpdateCaption;
end;

procedure THread.execute;
begin
//делаем что то долго, циклов тут нет...
end;

procedure THread.stop(var Msg: TMessage);
begin
case Msg.WParam of
0 : Suspend;
1 : Resume;
2 : Terminate;
end;
end;

//создаем тред
procedure TForm1.Button1Click(Sender: TObject);
begin
with Thread.Create(true) do
begin
Form1._Handle := Handle;
resume;
end;
end;

//посылаем ему команду, чтоб он умер, но нифига не получется,
//хотя, повторюсь в уже написанной проге так работает!
procedure TForm1.Button2Click(Sender: TObject);
begin
PostMessage(_Handle, wm_stop_thread, 2, 0);
//SendMessage и PostThreadMessage дают тот же результат
end;


 
troits   (2001-11-28 16:41) [1]

Посмотри на реализацию terminate. Там просто выставляется флаг.
Ты уж сам должен выходить из Execute, если этот флаг выставлен.


 
Evgeniy_S   (2001-11-28 16:54) [2]

ну если бы в екзекуте у меня було:
repeat
...
until terminated
тогда да, но нету у меня там циклов, это во первых во вторых смотри выше, эта фигня уменя уже в откомпиленом проекте работает, просто повторить не получется почему то ...


 
troits   (2001-11-28 17:30) [3]

Подожди, я повнимательней посмотрел на твой код, и
не понял, как ты собираешься вызывать procedure stop.
TThread - это не окно.


 
Digitman   (2001-11-28 17:32) [4]


const
const tm_terminate_thread = wm_user + ...;


type

TMyThread = class (TThread)
...
protected
...
procedure execute;override;
...
public
destructor Destroy; override;
end;


TForm1 = class(TForm)
...
public MyThread: Thread
...
end;

implementation

destructor TMyThread.Destroy;
begin
if not Suspended then
PostThreadMessage(ThreadId, tm_terminate_thread, 0, 0);
inherited Destroy;
end;

procedure TMyThread.Execute;
begin
if not Terminated and not PeekMessage(0, tm_terminate_thread, 0, 0, PM_REMOVE) then
SomeShortStatementSequence1
else
Exit;
if not Terminated and not PeekMessage(0, tm_terminate_thread, 0, 0, PM_REMOVE) then
SomeShortStatementSequence2
else
Exit;
if not Terminated and not PeekMessage(0, tm_terminate_thread, 0, 0, PM_REMOVE) then
SomeShortStatementSequenceN
else
Exit;
//... и т.д., раз уж цикл не устраивает
end;

procedure TForm1.CreateSuspendedThreadButtonClick(Sender: TObject);
begin
MyThread := TMyThread.Create(true);
end;

procedure TForm1.SuspendThreadButtonClick(Sender: TObject);
begin
MyThread.Suspend;
end;

procedure TForm1.ResumeThreadButtonClick(Sender: TObject);
begin
MyThread.Resume;
end;

procedure TForm1.SafeTerminateThreadButtonClick(Sender: TObject);
begin
MyThread.Free;
end;

procedure TForm1.KillThreadButtonClick(Sender: TObject);
begin
MyThread.Suspend;
MyThread.Free;
end;


 
Evgeniy_S   (2001-11-28 17:43) [5]

>troits ©
дык ведь фунциклирует как то ...

>Digitman ©
спасибо за обширный ответ, но суть не в том , что меня цикл не устраивает, я бы его с радостью запихнул, да некуда, просто я в треде тяну страницу, и делаю соответственно HTTP.Get(url), (пользую я для этого indy), и пока он ее не вытянт, код дальше не выполняется, и вот собственно задача была обломить этод тред, в процессе закачки (тобиш в любой удобный момент)


 
troits   (2001-11-28 17:45) [6]

>Digitman
Все круто, только немного напутано с PeekMessage ?


 
Evgeniy_S   (2001-11-28 17:50) [7]

>Digitman
ну как тебе сказать, перед HTTP.GET(url) проверять смысла нет, а кокгда он отсосет страницу то сам таерминатится, а хочется прерывать процесс засоса, вот и спраивается куда в этом случае вставлять проверку на terminated?


 
Evgeniy_S   (2001-11-28 17:55) [8]

ЗЫ: и просто очень интересно, почему один раз получилось и работает, а больше не хочет :(((


 
troits   (2001-11-28 17:57) [9]

Может, проще использовать TerminateThread ?

Для того, чтобы stop вызвался, надо было вызвать Dispatch(Msg)


 
Evgeniy_S   (2001-11-28 18:02) [10]

>troits ©
>Может, проще использовать TerminateThread ?
ну дык это уже насилие, а так делаеш просто http.disconnect + terminate и усе, а Dispatch(Msg) я не вызывал


 
Digitman   (2001-11-28 18:12) [11]

>troits
ну, первым параметром еще экз-р структуры TMsg надо указать - согласен, пропустил его.

>Evgeniy_S
Понятия не имею, как у тебя все это работало вообще. Хэндл потока не тоже самое, что и хэндл окна, и сообщения в твоем варианте ты пытаешься слать, используя именно хэндл потока в качестве адресата посылаемых сообщений, что неверно да и бессмысленно.

вот этой процедурой

procedure TForm1.KillThreadButtonClick(Sender: TObject);
begin
MyThread.Suspend;
MyThread.Free;
end;

поток будет безусловно принудительно уничтожен, но ты сильно рискуешь с утечкой ресурсов, обрывая поток при выполнении им блокирующего HTTP.Get()


 
Evgeniy_S   (2001-11-28 18:23) [12]

чесс слово работает (могу даже исходники показать), правда форма со веми этими делами в длл лежит, хотя сомнительно что это может влиять.


 
Digitman   (2001-11-28 18:28) [13]

>Evgeniy_S
Значит, код, что ты привел, не соответствует оригиналу.
А, если соответствует, объясни тогда, что ты делаешь здесь:


procedure TForm1.Button1Click(Sender: TObject);
begin
with Thread.Create(true) do
begin
Form1._Handle := Handle; // зачем здесь Form1 ? этот объект текущий. В его поле _Handle ты записываешь хэндл только что созданного потока, а не какого-то окна
resume;
end;
end;


и здесь :


procedure TForm1.Button2Click(Sender: TObject);
begin
PostMessage(_Handle, wm_stop_thread, 2, 0); // ???????????
end;



 
Evgeniy_S   (2001-11-28 18:39) [14]

>Form1._Handle := Handle; // зачем здесь Form1 ? этот объект текущий
абсолютно не нужен, просто так
>PostMessage(_Handle, wm_stop_thread, 2, 0);
ну, скажем так, раньше я думал что посылаю треду такое сообщение (теперь уже и не знаю), и причем оно посылается, хотя как я тоже не знаю


 
Digitman   (2001-11-28 18:56) [15]

так, если даже так (считаешь, что посылаешь потоку сообщение), тогда :

1. Какого же черта обработчик сообщения ты объявляешь и реализуешь в форме, а не в классе потока ?? Она имеет свое окно и реагирует только на сообщения ей самой или гл.окну приложения.

2. Посылать потоку сообщение нужно вызовом PostThreadMessage(c параметром ThreadId, а не ThheadHandle), а PostMessage шлет сообщение только окну (параметр - WindowHandle, а не ThreadHandle)

3. Почему ты уверен, что сообщение посылается вызовом PostMessage() ? Где анализ результата вызова ? Он ведь - Boolean, и будет True только если сообщение реально помещено в очередь указанного (и существующего!) приемника

4. Даже если бы каким-то невероятным образом сообщение оказалось в очереди сообщений потоку, где в теле Thread.Execute ты делаешь выборку этих сообщений из очереди ? Все, что ты там делаешь - это HTTP.Get(), и ничего более. Поток сам ответственен за выборку и обработку сообщений из собственной очереди сообщений. А эта очередь инициализируется ТОЛЬКО после любого из вызовов GetMessage, PeekMessage, сделанных в коде потока.



 
iZEN   (2001-11-28 19:45) [16]

/**Evgeniy_S (28.11.01 16:13):
<...>
procedure THread.execute;
begin
//делаем что то долго, циклов тут нет...
end;
<...>
*/

А как поток узнает что он терминировался из другого места?
Так вот, где-то в execute() должна происходить проверка флага на остановку. Но, так как в коде execute() нет таких проверок, то и поток будет жить, пока не выйдет из execute(), то есть пока не выполнит свою задачу доконца.

Ввыход 1: создать второй поток (Watcher) и читать данные первого работающего потока без синхронизации, если возможно, или с синхронизацией обновляемых данных в критической секции. Но в этом случае, первый поток всё равно нельзя остановить, так как в execute() нет витков-циклов и он, как я понял со слов автора и сделал вывод, не может в любое время узнать о своём терминировании.

Выход 2: опять повторюсь, без call-back-оповещений работающего потока остановить его невозможно. И дело не в WinAPI.


 
Evgeniy_S   (2001-11-29 11:53) [17]

>Digitman ©
>обработчик сообщения ты объявляешь и реализуешь в форме
да нет же, он в классе треда определен
>сообщение нужно вызовом PostThreadMessage(c параметром ThreadId, а не >ThheadHandle)
и так я пробовал, всеравно
>Почему ты уверен, что сообщение посылается вызовом ...
да я говорю, что уже и не уверен, но ить работает же как то

>iZEN
>А как поток узнает что он терминировался из другого места?
вот в этом проблема и стоит, как ему об этом сказать


Ну и главный вопрос, как же тогда это реализовать? Ведь делают же как то такие штуки? Поможите плиз...


 
paul_shmakov   (2001-11-29 11:56) [18]

прошу прощения, что не в тему, но лучше использовать асинхронный ввод/вывод. тем более для http.get. не знаю, позволяют ли компоненты indy использовать асинхронный io. ics, например, позволяют. их и рекомендую.


 
Evgeniy_S   (2001-11-29 12:13) [19]

>paul_shmakov ©
а где лежит сей ics ?


 
paul_shmakov   (2001-12-02 02:08) [20]

2 Evgeniy_S:
http://www.overbyte.be


 
XCreator   (2001-12-02 05:22) [21]

Да, действительно крутой компонент. Гораздо лучше FastNet"овского.
Кстати, прошу прощения за оффтопик, никто не знает, что за исключение EJPEG? У меня прога получает картинки с нета, и при отображении появляется это исключение. В результате поисков не в хелпе, не в инете ничего не нашел.



Страницы: 1 вся ветка

Текущий архив: 2002.01.31;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.011 c
3-99890
Sashka
2001-12-28 01:32
2002.01.31
component for MSSql & MySql


3-99838
victor
2001-12-25 06:55
2002.01.31
не отображаются значения по умолчанию


3-99835
Андрей К.
2001-12-25 09:38
2002.01.31
FreeReport для Delphi 6


7-100074
Win
2001-10-19 16:19
2002.01.31
Как прогу скопировать7


1-100008
Gilbert
2002-01-14 08:44
2002.01.31
Компонент Label который показывает системное время