Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Прикол с TThread


Страницы:   1 2 3 4

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 выполняется в главном потоке. ;)
А почему виснет при выходе пройдись пошагово, посмотри что происходит.


Страницы:   1 2 3 4

Наверх

Титульная страница Поиск, карта сайта Написать письмо