![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Прикол с TThread
Separator © (2002-11-20 13:10:00)
type
TMyThread = class(TThread);
protected
procedure Work;
procedure Execute; override;
end;
var
Form1: TForm1;
MyThread: TMyThread;
implementation
procedure TMyThread.Work;
begin
//что-нибудь делаю, главное чтоб это делалось долго
end;
procedure TMyThread.Execute;
begin
repeat
Synchronize(Work);
until Terminated
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
MyThread:= TMyThread.Create(false)
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
MyThread.Terminate;
MyThread.Free;
end;
end;
Если Form1.Destroy происходи когда идет работа в процедуре Work, то приложение виснет. Почему?
Если убрать Synchronize, то тогда все нормально.
reonid (2002-11-21 12:19:00) [41]Fantasist © (21.11.02 11:18)
Типичнейший, ИМХО, дедлок:
MyThread выполняет Synchronize -
т.е. посылает (SendMessage) CM_EXECPROC
специальному окну основного потока, останавливается
и ждёт, пока сообщение будет обработано.
А основной поток в это время занят обработкой
WM_CLOSE, пришедшее для основной формы
(в результате вызывается OnClose), и пока
он его не обработает, он не обработает, он не
займётся CM_EXECPROC.
Но в процессе выполнения OnClose он вызывает
деструктор TMyThread - который, в свою очередь,
вызывает WaitFor - теперь основной поток останавливается
и ждёт, когда закончится MyThread, который ждёт, когда основной поток обработает его CM_EXECPROC.
Всё. Мат в два хода.
Smithson (2002-11-21 12:09:00) [42]//Fantasist ©
Не сочти за наезд, но здесь форум, то бишь школа. Человек задал вопрос, ему накидали вариантов, он что-то нашел и решил задачу. Вот я и прошу выложить решение, что бы потом можно было сюда отсылать следующего с таким же вопросом. Правда, ты и Zemal ответ разжевали, так что мое желание выполнено.
//Zemal
Sorry за offtop
Zemal (2002-11-21 12:07:00) [43]Кстати, этот пример (который тут разбирается) шаблон из FAQ что-ли? Даааа... бывают и придурки, которые FAQ пишут! Этож надо додуматься! Создавать поток для многократного запуска процедуры в VCL потоке! Такой дури я ещё в FAQ не встречал! Separator, поделись где ты откапал такую пургу?
Zemal (2002-11-21 11:59:00) [44]Даааа... ну и дела... я в задумках... Separator, ты отдельно живёшь от своего мозга? Зачем выносить вопрос на форум, если ты уже решил проблему? Возьми книгу, почитай. Или в FAQ поищи. А когда наберётся в головёнке большая часть информации - тогда и проясниться всё, тогда и всё сразу станет понятно. И нечего отвлекать людей по глупостям. Это же элементарная теория потоков!
>>Если Form1.Destroy происходи когда идет работа в процедуре
>>Work, то приложение виснет. Почему?
А почему ты неможешь работать и идти домой одновременно? Посмотри ещё дополнительно информацию про сообщения, наверняка незнаешь как происходит закрытие приложения и что такое стек сообщений главного окна приложения.
>> procedure TMyThread.Work;
>> begin
>> //что-нибудь делаю, главное чтоб это делалось долго
>> end;
Потоки и должны выполнять это самое "долго". Нафига тебе понадобилось грузить VCL поток? Единственное, что у тебя будет выполняться в твоём потоке, так это только то что описано в Execute, остальные вызовы будут в VCL потоке выполняться. И естественно, когда VCL поток загружен работой, то он и будет производить впечатление зависшего приложения (на самом деле оно не висит, а лишь поуши в работе).
И что вам всем лень почитать? Выносите на форум и что надо и что ненадо... лишь бы было. У тебя же были зацепочки твоей проблемы, мог бы взять и раскрутить (поискать FAQ, полистать книгу). Другое дело, когда незнаешь почему и не знаешь что и где искать - тогда люди помогут, а по пустякам людей беспокоить нестоит - боком может выйти.
Fantasist (2002-11-21 11:37:00) [45]
> дэдлок? ;))
Не, deadlock - это когда два(или более) объекта ждут друг друга. В этом же случае, поток просто ждет, того, чего уже нет.
MyEN (2002-11-21 11:26:00) [46]дэдлок? ;))
Fantasist (2002-11-21 11:19:00) [47]Вообще мне VCL-евская синхронизация не очень нравиться.
Fantasist (2002-11-21 11:18:00) [48]
> Smithson © (21.11.02 09:01)
> Ну и?
А что тут не понятного? Вызывается Work в основном потоке - тыкаем закрыть форму - сообщение об этом помещается в очередь сообщений и висит там, пока Work не закончит работать. После этого - главное окно сразу же закрывается и по видимому закрывается тот механизм, что обеспечивает работу Synchronize (не помню точно как у них - кажись через сообщения и какие-то глобальные переменные). Сам поток не прекращает выполнение(по видимому он успевает пройти через "until Terminated" до того, как главный поток изменяет это значение) и доходит до Synchronize(Work) после чего начинает ждать пока основной поток вызовет и отработает этот Work, чего тот никогда не делает.
MetalFan (2002-11-21 11:15:00) [49]to Separator
ага, мне тож интересно)))
где ошибка то?
Smithson (2002-11-21 09:01:00) [50]Ну и?
Separator (2002-11-21 08:41:00) [51]ДА
Digitman (2002-11-21 08:32:00) [52]>Separator
Ну так ты выяснил - почему ?
Separator (2002-11-21 08:00:00) [53]
> Digitman © (20.11.02 13:38)
Вполне согласен, просто я хотел поинтересоваться почему так происходит. Я уже давно решил эту проблему. Всем спасибо
Digitman (2002-11-20 13:38:00) [54]Руки бы поотрывать тому, кто этот пример "запустил" в FAQ как программный шаблон, которому неукоснительно надо следовать при работе с TThread.
А заодно и головы тем, кто с завидной регулярностью совершенно бездумно, не вникая в суть и не читая документацмм, "сдирает" этот пример и после этого заваливает форум вопросами про якобы "приколы".
asmith (2002-11-20 13:36:00) [55]Проблема в том, что вызов MyThread.Terminate не останавливает поток, а только сигнализирует ему, что нужно остановиться, устанавливая свойство Terminated в True. Поэтому для уничтожения потока вызовом MyThread.Free нужно дождаться завершения потока. Проще всего этого добиться установкой FreeOnTerminate в True при создании и все.
Ice Scream (2002-11-20 13:24:00) [56]destructor TMyThread.Destroy;
begin
if Suspended then Resume else Suspend;
Terminate;
end;
Слесарь Матерящийся (2002-11-20 13:23:00) [57]>просто виснет
Вполне логично.
Separator (2002-11-20 13:21:00) [58]
> NailS © (20.11.02 13:18)
проходил и не раз, ничего не происходит, просто виснет
Какой ужас (2002-11-20 13:20:00) [59]Процедуры, которые вызываются через Synchronize,
на самом деле вызываются из основного потока.
При этом твой поток останавливается и ждёт, когда
основной выполнит эту процедуру.
(А основной поток при этом может ждать, когда окончится твой поток - так он и делает при разрушении объекта TMyThread)
Надо в Synchronize выносить только то, что не рекомендуется делать пользовательском потоке - в основном, это
обновление интерфейса. Это должны быть короткие процедуры.
NailS (2002-11-20 13:18:00) [60]>Synchronize(Work);
И процедура Work выполняется в главном потоке. ;)
А почему виснет при выходе пройдись пошагово, посмотри что происходит.