![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Создание двух потоков [D5, Win2k]
tiam © (2002-12-24 14:49:00)Добрый день.
Кто может привести краткий и понятный код, либо дать ссылку, как пример работы двух потоков, например, в одном идут вычисления и вывод на битмап, а в другом, в это же время ввод данных в едит.
Те примеры, что видел, не очень наглядны, слишком запутаны, как, например, этот: http://delphi.mastak.ru/articles/panov/index.html.
Стандартный демопример из Делфи тоже не слишком нагляден.
Спасибо.
tiam (2002-12-25 14:32:00) [21]А что такое MyThread?
У меня поток создается так.
type
tmystream = class(TThread)
myProcess:=stream.TMystream.Create(true);
А если так написать: tmystream.Free, то ругается: "Этот метод только для методов классов"
Digitman (2002-12-25 14:18:00) [22]if Msg.message = WM_KEYDOwn then
begin
//сначала вызываем деструктор объекта, управляющего доп.потоком
MyThread.Free; // не путай понятия process и thread ! У тебя именно дополнительный thread уже работающего процесса
//и только затем даем команду процессу на завершение
Application.Terminate;
end;
Процесс не завершится до тех пор, пока не завершен хотя бы один из доп.потоков, созданных в ходе работы процесса.
Т.е., перед командой на завершение приложения (читай - процесса, в контексте которого приложение работает в дан.момент), ты обязан принять меры к корректному терминированию ВСЕХ созданных тобой доп.потоков
В ходе выполнения MyThread.Free перед разрушением объекта TMyThread будет вызван метод Terminate() базового класса (TThread).
Все, что делается в методе Terminate() - взводится некий внутренний флаг (поле TThread.FTerminated получает значение True)
Код работающего потока в теле метода Execute() имеет доступ к состоянию этого флага через св-во TThread.Terminated.
Выполняющий длит.вычисления поток должен КАК МИНИМУМ периодически контролировать состояние св-ва Terminated для того, чтобы "поймать" момент, когда от потока кто-то извне требует как можно быстрей "закруглиться". Как только алгоритм метода Execute() обнаружит условие Terminated = True, он ОБЯЗАН как можно быстрей завершить выполнение (процедура Execute должна быть как можно быстрей завершена)
sel (2002-12-25 13:54:00) [23]2 POlevi
Application.Terminate уничтожает все потоки порожденные самим этим application?
Проверку нажатия клавиши куда лучше поставить в главном модуле?
По таймеру? И нужно ли в данном случае синхронизироваться?
а в самом потоке, в execute, писать таким образом?
procedure tmystream.Execute;
while not terminated do
begin
dosmth(form1.Memo1.Lines, form1.PaintBox1);
dosmthelse(form1.Memo1.Lines, form1.PaintBox1);
end;
end;
Polevi (2002-12-25 13:39:00) [24]>tiam (25.12.02 13:35)
В самом потоке происходит подготовка битмапа и вывод.
Synchronize() я не делаю, так как не совсем понял с чем в моем случае нужно синхронизироваться
- синхронизироваться должно обращение к VCL
в главной форме:
if Msg.message = WM_KEYDOwn then
begin
MyProcess.WaitFor;
application.Terminate;
end;
Polevi (2002-12-25 13:36:00) [25]Use this routine or a TThread object to spawn separate threads of execution instead of calling the CreateThread Win32API directly. BeginThread encapsulates the Win32 CreateThread API call, but unlike CreateThread, it sets the global IsMultiThread variable, thereby making the heap thread-safe.
IsMultiThread is set to True by BeginThread in order to allow the memory manager to execute safely if a VCL application has more than one thread. If a second thread attempts to allocate memory, it is blocked until the first thread exits the memory manager.
tiam (2002-12-25 13:35:00) [26]2 Digitman
Делаю программу, которая должна закрываться при нажатии клавиши (по типу screensaver), так как расчет перед выводом на битмап занимает много времени, то его и пытаюсь загнать в отдельный процесс.
unit stream; // модуль потока
type
tmystream = class(TThread)
Создание потока в главном модуле:
MyProcess:=stream.TMystream.Create(true);
MyProcess.Priority:=tpLower;
MyProcess.Resume;
В самом потоке происходит подготовка битмапа и вывод.
Synchronize() я не делаю, так как не совсем понял с чем в моем случае нужно синхронизироваться
в главной форме:
if Msg.message = WM_KEYDOwn then
begin
application.Terminate;
MyProcess.Terminate;
end;
То есть, при нажатии клавиши вся программа прекращает работу, и поток останавливается.
Так ли это?
Поток останавливается в разных состояниях (выводит то весь текст, то часть его), хотя клавиши не нажимаю. В каких случаях поток может прекратить работу?
И еще вопрос:
Действительно ли удобнее использовать API ф-ии для работы с потоками?
Спасибо
Александр Спелицин (2002-12-25 12:10:00) [27]2Alex Konshin
> используйте BeginThread/EndThtread, а не CreateThread.
Простите, а где именно могут быть грабли при использовании CreateThread?
Digitman (2002-12-25 12:02:00) [28]
> поток должен остановиться
Что значит "остановиться" ? И зачем ему останавливаться, если он занимается обработкой данных ? Поясни
tiam (2002-12-25 11:53:00) [29]Допустим, поток должен остановиться в случае событий клавиатуры.
Почему выполнение потока приостанавливается самопроизвольно
tiam (2002-12-25 11:17:00) [30]А как грамотно уничтожить поток после выполнения
Alex Konshin (2002-12-25 05:47:00) [31]Еще раз: используйте BeginThread/EndThtread, а не CreateThread.
Для конкретно этого примера это может и не критично, но потом люди глядя на этот пример нарвутся на грабли.
drin (2002-12-25 04:19:00) [32]Thread слишком сильно запутан, как по мне, я же использую API ф-ии, для работы с потоками, пример:
Var
hThr1, hThr2: THandle;
ThrID1, ThrID2: DWORD;
...
procedure My_Proc1;
begin
while true do
begin
ShowMessage("Proc 1");
sleep(10000);
end;
end;
procedure My_Proc2;
begin
while true do
begin
ShowMessage("Proc 2");
sleep(3000);
end;
end;
begin
hThr1:=CreateThread(nil, 0, @My_Proc1, nil, 0, ThrID1);
hThr2:=CreateThread(nil, 0, @My_Proc2, nil, 0, ThrID2);
end;
Всё что выполняется в ф-ях My_Proc1, My_Proc2 выполняется паралельно между собой и с тем что выполняется в основном потоке в том числе и прорисовка.
Тоесть каждые 10 сек будет выскакивать сообщение "Proc 1",
каждые 3 сек будет выскакивать сообщение "Proc 2" и при этом прорисовка и обновление главной формы не приостановятся.
tiam (2002-12-24 15:45:00) [33]2 digitman.
Спасибо...
sniknik (2002-12-24 15:42:00) [34]похоже я ошибался насчет описания. :о))
Digitman (2002-12-24 15:39:00) [35]
> Надо ли создавать отдельный юнит (new/thread object)
Не обязательно. Класс потока можно декларировать и реализовать в любом удобном для тебя юните, в т.ч. и отдельном.
Меню "new/thread object" предназначено всего лишь для запуска эксперта, который (для твоего удобства лишь) заведет отдельный юнит в проекте, "набъет" там декларацию нового класса-наследника TThread и реализацию-"заготовку" метода Execute()
В теле "заготовки" делай длительные вычисления.
После того, как Execute() завершит свою работу, поток так же завершается.
> опрос клавиатуры и вывод какой-либо
На то есть уже один поток - основной. Это его задача - ввод/вывод - и он с этим успешно справляется, так что - никаких доп.забот по этому поводу
Забота у тебя одна - выполнить, например, в цикле от 1 до 99 999 999 что-то. Если это делать "в лоб", в одном из обработчиков событий той же формы, то все это будет выполняться в осн.потоке, при этом все прочие события (например, ввода/вывода) будут ждать своей очереди на обработку и форма как бы "зависнет" на время выполнения цикла, не реагируя ни на мышь ни на клаву и не рисуя ничего на своей канве (это же и есть обработка событий ввода/вывода !)
В подобном случае есть смысл "вынести" тело цикла в доп.поток, в тело процедуры Execute(). Будучи сконструированным тобой в нужный момент времени (TMyThread.Create(..)), новый объект-наследник TMyThread = class(TThread) даст команду ОС на запуск в твоем процессе нового доп.код.потока и известит тебя о фактическом начале его работы вызовом процедуры Execute(). Все, что ты предусмотрел в теле этой процедуры, будет выполняться параллельно с работой других код.потоков процесса, в т.ч. основного. Т.е. ввод/вывод в осн.потоке - сам по себе, а цикл в твоем доп.потоке - сам по себе, совершенно независимо друг от друга.
sniknik (2002-12-24 15:39:00) [36]посмотри ссылку
http://gurin.tomsknet.ru/gala.html
там правда основа собственный компонент но лутшего описания потоков я не вилел, примеры есть и простые можно легко переделать на стандартные.
tiam (2002-12-24 15:29:00) [37]Так никто с ответом не поможет?
tiam (2002-12-24 15:16:00) [38]2 bak
Да, пожалуйста, на tiam@rambler.ru
tiam (2002-12-24 15:10:00) [39]Слишком много действий в коде (демопример Делфи), теряется сама тема за сортировой и массивами. Надо ли создавать отдельный юнит (new/thread object). А в примере http://delphi.mastak.ru/articles/panov/index.htmlне везде четко указано, что и где размещать, путаница с названиями юнитов, лучше бы просто исходники были примера.
Поэтому и прошу пример простейший. Два действия, выполняемых одновременно (опрос клавиатуры и вывод какой-либо), так как столкнулся с проблемой при большом количестве вычислений, программа не реагирует на нажатия клавиш, несмотря на всевозможные "process messages".
Итак,
Как разделить ввод и вывод на 2 потока, как потоки инициализировать (это вроде понятно) и выполнить в них простейший код?
Где еще статьи на эту тему для начинающих?
Спасибо.
bak (2002-12-24 15:06:00) [40]у меня есть простейший пример использования 2х потоков - изменяют прогресс в гаудже. Прикрутить другие процедуры я думаю не составит труда. Хошь - намылю.