Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2002.12.02;
Скачать: [xml.tar.bz2];

Вниз

Прикол с TThread   Найти похожие ветки 

 
Separator   (2002-11-20 13:10) [0]

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, то тогда все нормально.


 
Skier   (2002-11-20 13:13) [1]

>Separator
Form1.Release ?


 
Separator   (2002-11-20 13:17) [2]


> Form1.Release
Это что такое?


 
NailS   (2002-11-20 13:18) [3]

>Synchronize(Work);

И процедура Work выполняется в главном потоке. ;)
А почему виснет при выходе пройдись пошагово, посмотри что происходит.


 
Какой ужас   (2002-11-20 13:20) [4]

Процедуры, которые вызываются через Synchronize,
на самом деле вызываются из основного потока.
При этом твой поток останавливается и ждёт, когда
основной выполнит эту процедуру.
(А основной поток при этом может ждать, когда окончится твой поток - так он и делает при разрушении объекта TMyThread)

Надо в Synchronize выносить только то, что не рекомендуется делать пользовательском потоке - в основном, это
обновление интерфейса. Это должны быть короткие процедуры.


 
Separator   (2002-11-20 13:21) [5]


> NailS © (20.11.02 13:18)
проходил и не раз, ничего не происходит, просто виснет


 
Слесарь Матерящийся   (2002-11-20 13:23) [6]

>просто виснет

Вполне логично.


 
Ice Scream   (2002-11-20 13:24) [7]

destructor TMyThread.Destroy;
begin
if Suspended then Resume else Suspend;
Terminate;
end;


 
asmith   (2002-11-20 13:36) [8]

Проблема в том, что вызов MyThread.Terminate не останавливает поток, а только сигнализирует ему, что нужно остановиться, устанавливая свойство Terminated в True. Поэтому для уничтожения потока вызовом MyThread.Free нужно дождаться завершения потока. Проще всего этого добиться установкой FreeOnTerminate в True при создании и все.


 
Digitman   (2002-11-20 13:38) [9]

Руки бы поотрывать тому, кто этот пример "запустил" в FAQ как программный шаблон, которому неукоснительно надо следовать при работе с TThread.
А заодно и головы тем, кто с завидной регулярностью совершенно бездумно, не вникая в суть и не читая документацмм, "сдирает" этот пример и после этого заваливает форум вопросами про якобы "приколы".


 
Separator   (2002-11-21 08:00) [10]


> Digitman © (20.11.02 13:38)
Вполне согласен, просто я хотел поинтересоваться почему так происходит. Я уже давно решил эту проблему. Всем спасибо


 
Digitman   (2002-11-21 08:32) [11]

>Separator

Ну так ты выяснил - почему ?


 
Separator   (2002-11-21 08:41) [12]

ДА


 
Smithson   (2002-11-21 09:01) [13]

Ну и?


 
MetalFan   (2002-11-21 11:15) [14]

to Separator
ага, мне тож интересно)))
где ошибка то?


 
Fantasist   (2002-11-21 11:18) [15]


> Smithson © (21.11.02 09:01)
> Ну и?


А что тут не понятного? Вызывается Work в основном потоке - тыкаем закрыть форму - сообщение об этом помещается в очередь сообщений и висит там, пока Work не закончит работать. После этого - главное окно сразу же закрывается и по видимому закрывается тот механизм, что обеспечивает работу Synchronize (не помню точно как у них - кажись через сообщения и какие-то глобальные переменные). Сам поток не прекращает выполнение(по видимому он успевает пройти через "until Terminated" до того, как главный поток изменяет это значение) и доходит до Synchronize(Work) после чего начинает ждать пока основной поток вызовет и отработает этот Work, чего тот никогда не делает.


 
Fantasist   (2002-11-21 11:19) [16]

Вообще мне VCL-евская синхронизация не очень нравиться.


 
MyEN   (2002-11-21 11:26) [17]

дэдлок? ;))


 
Fantasist   (2002-11-21 11:37) [18]


> дэдлок? ;))


Не, deadlock - это когда два(или более) объекта ждут друг друга. В этом же случае, поток просто ждет, того, чего уже нет.


 
Zemal   (2002-11-21 11:59) [19]

Даааа... ну и дела... я в задумках... Separator, ты отдельно живёшь от своего мозга? Зачем выносить вопрос на форум, если ты уже решил проблему? Возьми книгу, почитай. Или в FAQ поищи. А когда наберётся в головёнке большая часть информации - тогда и проясниться всё, тогда и всё сразу станет понятно. И нечего отвлекать людей по глупостям. Это же элементарная теория потоков!

>>Если Form1.Destroy происходи когда идет работа в процедуре
>>Work, то приложение виснет. Почему?

А почему ты неможешь работать и идти домой одновременно? Посмотри ещё дополнительно информацию про сообщения, наверняка незнаешь как происходит закрытие приложения и что такое стек сообщений главного окна приложения.

>> procedure TMyThread.Work;
>> begin
>> //что-нибудь делаю, главное чтоб это делалось долго
>> end;

Потоки и должны выполнять это самое "долго". Нафига тебе понадобилось грузить VCL поток? Единственное, что у тебя будет выполняться в твоём потоке, так это только то что описано в Execute, остальные вызовы будут в VCL потоке выполняться. И естественно, когда VCL поток загружен работой, то он и будет производить впечатление зависшего приложения (на самом деле оно не висит, а лишь поуши в работе).
И что вам всем лень почитать? Выносите на форум и что надо и что ненадо... лишь бы было. У тебя же были зацепочки твоей проблемы, мог бы взять и раскрутить (поискать FAQ, полистать книгу). Другое дело, когда незнаешь почему и не знаешь что и где искать - тогда люди помогут, а по пустякам людей беспокоить нестоит - боком может выйти.


 
Zemal   (2002-11-21 12:07) [20]

Кстати, этот пример (который тут разбирается) шаблон из FAQ что-ли? Даааа... бывают и придурки, которые FAQ пишут! Этож надо додуматься! Создавать поток для многократного запуска процедуры в VCL потоке! Такой дури я ещё в FAQ не встречал! Separator, поделись где ты откапал такую пургу?


 
Smithson   (2002-11-21 12:09) [21]

//Fantasist ©
Не сочти за наезд, но здесь форум, то бишь школа. Человек задал вопрос, ему накидали вариантов, он что-то нашел и решил задачу. Вот я и прошу выложить решение, что бы потом можно было сюда отсылать следующего с таким же вопросом. Правда, ты и Zemal ответ разжевали, так что мое желание выполнено.

//Zemal
Sorry за offtop


 
reonid   (2002-11-21 12:19) [22]

Fantasist © (21.11.02 11:18)

Типичнейший, ИМХО, дедлок:

MyThread выполняет Synchronize -
т.е. посылает (SendMessage) CM_EXECPROC
специальному окну основного потока, останавливается
и ждёт, пока сообщение будет обработано.

А основной поток в это время занят обработкой
WM_CLOSE, пришедшее для основной формы
(в результате вызывается OnClose), и пока
он его не обработает, он не обработает, он не
займётся CM_EXECPROC.

Но в процессе выполнения OnClose он вызывает
деструктор TMyThread - который, в свою очередь,
вызывает WaitFor - теперь основной поток останавливается
и ждёт, когда закончится MyThread, который ждёт, когда основной поток обработает его CM_EXECPROC.

Всё. Мат в два хода.


 
Zemal   (2002-11-21 12:32) [23]

to Smithson
Да чего мы тут разжевали-то! Разьве этого хватит? Мы только ещё раз подтолкнули к литературе и FAQ, а чего надо было искать Separator и без этого знал... мог бы и без нас найти ответ на эту проблему. Просто лень забивает :(, а это плохо... очень плохо... ленивый программист хуже футболиста (из анекдота: Жили-были дед и бабка и было у них три сына - два умных, а третий футболист).

to Separator
Больше читать надо... вот к чему я веду. По другому только людей на форуме раздражать будешь и это всё чего сможешь добиться. Разьве мало литературы? Или ты выше этого? А вообще-то, зачем тебе она впёрлась, если на форуме за тебя весь код напишут... логика железная.

to All
Советую всем кто плохо знает потоки изучить одну библиотечку, там очень хороший и доступный самоучитель и класная справка (всё на русском). Вот ссылка: http://gurin.tomsknet.ru/gala.html
Скачивайте оттуда библиотеку Gala и пользуйтесь наздоровье, там представлены решения всех возможных проблем с потоками, а при более глубоком рассмотрении библиотеки вы сможете создавать потоки непосредственно виндовые (и забудете про класс TThread напрочь :) ).


 
Smithson   (2002-11-21 12:34) [24]

>> Zemal
Вертел я как-то эту галу, вертел - и вернулся к TThread + немного API. Так что оно на любителя.


 
Zemal   (2002-11-21 12:36) [25]

to Reonid
Ловко! Молодец! Ты хороший гросмейстер! :) Однозначно дедлок потока TMyThread с VCL-потоком :). Хорошо ты разжевал... с подробностями и смакуя :). Молодец!


 
Digitman   (2002-11-21 12:44) [26]

> reonid © (21.11.02 12:19)

> MyThread выполняет Synchronize -
> т.е. посылает (SendMessage) CM_EXECPROC
> специальному окну основного потока, останавливается
> и ждёт, пока сообщение будет обработано.

Да мало того - по кр.мере в Д5 это тоже далеко не всегда соответствует действительности. Именно - "специальному окну основного потока".

Если самый первый объект класса TThread в свою очередь сам был создан в доп.код.потоке, то и окно будет принадлежать потоку , вызвавшему конструктор. А это значит, что осн.код.поток по-умолчанию не будет выбирать и диспетчеризовать сообщения окна, не им созданного. Иными словами, WaitFor, вызванный в дан.случае в осн.код.потоке даст совершенно неожиданный и неверный результат.


 
Zemal   (2002-11-21 12:45) [27]

to Smithson
Я и непредлагаю тебе её дальше вертеть :). Это я тем, кто незнает что такое потоки. Gala - хороший самоучитель и в примерах разбирает множество проблем синхроницации и обмена данными между потоками (семафоры, мьютексы, посылка сообщений, проблема дедлока и т.д.). Я и сам тоже пользуюсь API и классом потока Win32 (Thread), когда нужно написать хорошую вещь и важно быстродействие и свободные ресурсы, а если для теста, то мона быстренько и на TThread набросать, можно и Gala поюзать... это действительно на любителя :), это ты прав :).


 
Zemal   (2002-11-21 13:02) [28]

to Digitman
Ну ты и замутил :). Мы разбераем простой пример с одним потоком и VCL-потоком. Подрозумевается, что сообщения от потока будет принимать главная форма приложения, т.е. VCL-поток, а не форма, динамически созданная потоком :). Можно ещё приплести форму из dll :). В определённых условиях всё так как описал Reonid. Эйнштейн ещё говорил, что всё в мире относительно и что является постулатом и аксиомой в одних условиях, может быть нарушено в других и даже перевёрнуто с ног на голову :). Ну ошибся Reonid в терминах, окно, владеющее потоком (Owner) назвал "специальным окном основного потока"... я думаю он просто оговорился :).


 
Digitman   (2002-11-21 13:11) [29]


> окно, владеющее потоком


Сударь, коль скоро ты начал развивать тему "неточностей", скажу уж, что при таком раскладе мог бы и сам недопускать новых "неточностей". Причем, imho, достаточно грубых.

Окно не может владеть потоком, строго наоборот - кодовый поток, в контексте которого был создан объект-окно, владеет эти окном.


 
Digitman   (2002-11-21 13:15) [30]

Здесь термин "владеет" означает как минимум одно (но - самое важное) : по-умолчанию лишь тот поток, который создал окно, имеет возможность получать сообщения, адресованные этому окну. Если не оговорены доп.требования (см. AttachThreadInput)


 
reonid   (2002-11-21 13:15) [31]

Digitman © (21.11.02 12:44)

Чесно говоря, я не задавался вопросом -
можно ли влезть вперёд паровоза и создать
свой объект TThread до того, как дельфи создаст
ВэЦээЛьный TThread.

Я подозреваю там какую-то химию - ведь сам винапишный поток
явно создан уже когда выполняется _StartExe, а объекта
TThread для него ещё вроде как нет.
Если это так, то такой финт ушами вполне возможен.
Не знаю, не прорабатывал глубоко этот вопрос...

Если это возможно, то ты, без сомнения, прав.
Но всё равно это исключительно редкий случай.


 
Digitman   (2002-11-21 13:36) [32]

случай далеко не редкий.

пусть ты создал в среде Делфи DLL, использующую VCL, и при исполнении одного из эксп.вызовов которой (Entry1) создается экз-р TThread (Thread2)

пусть в Thread2.Execute выполняется Synchronize() для каких-то целей (разумеется, целей синхронизации неких известных методов с осн.потоком)

пусть эту DLL использует некий хост-процесс с MainThread= Thread0 , не использующий VCL и создающий доп.поток (Thread1) неким иным образом, например, прямым вызовом WinAPI CreateThread()

пусть в ходе выполнения Thread1 происходит обращение к Entry1.
при этом будет впервые вызван конструктор Thread2 := TThread.Create(...), в рез-те чего в потоке Thread1 будет создано невиз.окно для адресации ему технолог.сообщений, в т.ч. CM_EXECPROC.

поскольку CM_EXECPROC послано окну, созданному в потоке Thread1, то и выбирать/обрабатывать это сообщение должен поток Thread1. Мало того, что в теле Thread1 может быть вообще не предусмотрен цикл выборки/диспетчеризации оконных сообщений, так он еще и занимается в этот момент исполнением тела Entry1 !

вот и получается самый настоящий "конфуз")


 
Zemal   (2002-11-21 13:40) [33]

to Digitman
Спасибо за разъяснения :). Мы уже доплясали до объекта Application, который владеет главным окном приложения, которое в свою очередь владеет дочерними окнами и дальше объекты по иерархии :). И я незнаю такого объекта "кодовый поток" и как он может владеть чем-то? Может я ещё не достиг такого просветления сознания?!
А сообщения (Message) может принимать только объект класса TForm и это означает, что поток должен принадлежать определённой форме приложения, которая и отвечает за приём сообщений в свой стек и за диспетчирезацию и обработку их. Разьве не так?
Кстати, что ты понимаешь под термином "кодовый поток" мне очень интересно, т.к. я не до конца понимаю.
P.S. Есть конечно события и уровня Application, т.к. это тоже форма, только никто и никогда её невидел, т.к. она неимеет клиентской части и преднозначена для приёма сообщений уровня Application (Application.OnMessage) и отображения приложения на панели задач (прямоугольничек такой с надписью). Всё, дальше продолжать небуду... долго, нудно и неохото :).


 
Борис   (2002-11-21 13:48) [34]

Я с этим примером тоже много мучился пока Digitman все неразжевал, а потом нашел хороший pdf про TThread.

Может этот пример воодще из FAQ убрать (по-моему он в статьях лежал) или заменить на верный, чтобы не вводить народ в заблуждение?


 
Digitman   (2002-11-21 13:52) [35]


>Zemal

термины "кодовый поток" и "thread" эквивалентны

см. GetWindowThreadProcessId, это даст тебе пищу для размышления и хоть какую-то определенность в понимании, кто кого "создает" и кто кем "владеет", когда речь идет не о VCL-объектах (TApplication , TForm и иже с ними), а об объектах ОС (window, process, thread e.t.c)

извини, но читать подробную лекцию на эту тему у меня нет ни времени ни желания.
Есть желание, есть книги, есть хэлп, есть MSDN - что еще надо человеку чтобы разобраться во всех этих потрохах до тонкостей ?)


 
Digitman   (2002-11-21 14:02) [36]


>Борис

> Я с этим примером тоже много мучился пока Digitman все неразжевал,

Видит бог - я старался)

> Может этот пример воодще из FAQ убрать (по-моему он в статьях
> лежал)

Да хрен его знает, где он "лежал" или "стоял", но, видать, и по сей день глаза мозолит все большему и большему числу программеров. Особливо - начинающих. То-то и беспокоит, ибо - "сдерут" его и понеслааааась басня Крылова про мартышек с очками) ...


>или заменить на верный, чтобы не вводить народ в
> заблуждение?

А любопытно, что есть "верный" пример ? Я таких не знаю. Просветишь может быть ?


 
Zemal   (2002-11-21 14:11) [37]

to Digitman
Спасибо за толчёк в нужном направлении, спасибо за пищу для размышлений :). Ты меня озадачил. У меня действительно образовалось много дыр и некоторая каша в голове :). Полезу выкапывать детали (основную мысль я ужо ухватил :), благодаря тебе). Всё, полез в MSDN, письма оттуда ходят медленно, а транспорт вообще неходит :), посему скоро не ждите.


 
Digitman   (2002-11-21 14:14) [38]

>Zemal

Терпения и успехов и тебе в постижении "непостижимого" !.........)


 
Zemal   (2002-11-21 14:17) [39]

to Digitman
Спасиб! :)


 
Борис   (2002-11-21 14:21) [40]

Digitman

Дык, так там получается, что вся работа все-равно выполняется в основном потоке (точнее основной останавливается, ожидая когда законитя другой). имхо.

А вот по-моему и ссылочка: http://delphi.mastak.ru/articles/thread/index.html

и вот тоже ссылочка
http://delphi.mastak.ru/articles/http/index.html

вообще вначале я изучал по этой статье и начались косяки, пришлось разбираться и вникать.



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

Форум: "Основная";
Текущий архив: 2002.12.02;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.009 c
8-4520
vasya_dvc
2002-08-07 22:45
2002.12.02
Почему Photoshop не понимает?


1-4388
Пташка
2002-11-22 11:06
2002.12.02
Помогите с решением!


4-4657
Tihas
2002-10-17 01:17
2002.12.02
Несколько вопросов...


6-4555
fffff
2002-10-05 11:49
2002.12.02
Delphi и Инет


7-4651
max2057
2002-09-30 13:01
2002.12.02
TdxMasterView and Drag-n-Drop





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский