Форум: "WinAPI";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.01.31;
Скачать: [xml.tar.bz2];




Вниз

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? У меня прога получает картинки с нета, и при отображении появляется это исключение. В результате поисков не в хелпе, не в инете ничего не нашел.




Форум: "WinAPI";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.01.31;
Скачать: [xml.tar.bz2];




Наверх





Память: 0.77 MB
Время: 0.027 c
1-99941           Yakudza               2002-01-12 16:22  2002.01.31  
Как добавить символ табуляции в строку ?


1-99982           roman001              2002-01-11 19:35  2002.01.31  
Эмуляция нажатия клавы


1-100002          Илья                  2002-01-15 09:48  2002.01.31  
RichEditControl


4-100104          Romul                 2001-12-02 10:59  2002.01.31  
Узнать количество файлов с помощью API


4-100106          maxi                  2001-12-02 14:15  2002.01.31  
Список задач по Alt-Ctrl-Del.