![]() |
Реализация многопоточности в delphi. Вижу множество вопросов на разных форумах по программированию которые относятся к многопоточности. В этой статье я бы хотел не только объяснить как реализовать это в delphi, но и предоставить готовый шаблон многопоточного приложения который вы бы могли использовать в дальнейшем в своих программах.Для начала немного теории. Одной из важнейших вещей в многопоточном приложении является синхронизация потоков. Если не учесть, синхронизацию потоков, то это, может привести к плачевным последствиям. Давайте рассмотрим такой пример, после чего у вас в голове всё встанет на свои места. У нас в программе имеется переменная, назовём её - "int" - типа integer. Если мы будем присваивать ей значение из основного потока, то всё будет хорошо, и проблем не возникнет. Мало того, если даже мы присвоим ей значение из дополнительного потока который мы создали, то всё будет хорошо. Но так как зачастую у многопоточного приложения более одного дополнительного потока, то зададимся вопросом- "А, что будет если мы попытаемся присвоить переменной значение из двух потоков одновременно?". Вот тут, и произойдёт то таинственное события при котором переменной присвоится значение которое скорее всего не будет равно ни одному из значений которых вы планировали ей присвоить. Тогда и вступает в игру метод синхронизации synchronize. С помощь данного нам разработчиками delphi метода, вы можете обеспечить безопасное обращение нескольких потоков к одной переменной. Данный метод обеспечивает следующие: при вызове процедуры с помощью synchronize она начинает выполнятся, а все остальные процедуры вызванные с помощью этого метода встают в очередь и ждут выполнения текущей процедуры. Всё вышеописанное относится только к записи переменных, а читать можно одновременно из нескольких потоков и ничего плохого не произойдёт. Ну а теперь перейдём к практике. И так создадим новый проект. И начнём писать поток. После вот этих строк: Код:
privateКод:
potok = class(TThread) //Этой строкой мы унаследовали класс потокаПод implementation нам надо описать конструкцию потока, в данном примере это не обязательно, но, что бы вы знали на будущие мы всё равно это сделаем. Код:
constructor potok.Create(CreateSuspended: Boolean);Код:
varКод:
procedure potok.Execute;//начинаем описывать главную процедуру потокаКод:
procedure TForm1.Button1Click(Sender: TObject);Код:
unit Unit1;С уважением Tip.the.besT. Автор: Tip.the.besT |
Так запускать поток
Цитата:
Synhronize гдето писали что лучше его не использовать для работы с глоб. переменными а только для синхронизации работы с формой. Описывать класс потока в одном юните с формой не ок. Шаблон этот создаетcя File->New->Other->ThreadObject Коментировать так детально код, не ок, все черты мешаються с кодом. Цитата:
|
Цитата:
Не знаю где писали про Synhronize, но если ты запустишь мой пример, то убедишься, что нормально всё с переменными. Интересно и как же описания потока в одном юните повлияет на работу программы? Конечно, тебе комментарии не нужны. А человеку придётся возвращаться выше и перечитывать, что бы понять. Итого. Достаточно было написать: "Добавь потоки в массив." |
Цитата:
|
Цитата:
Цитата:
Цитата:
Зачем переопределять конструктор?? Если в нем нечего не происходит? Цитата:
А нужно в приват, это правило хорошего тона что не юзаеться напрямую извне совать в привате. И одна из таких кому то мб и не покажеться проблемой. Когда мы объявляем данные в Private секции они доступны классам и т д, объявленным в том же юните, соответственно безопасность работы с классом нарушается, ну и автоподстройка будет выдавать приват члены класса, а на сонную голову из-за этого можно потом долго ошибку ловить. Ну и одно из важнейших замечаний при работе с потоками ты не указал надо обрабатывать все Except-шены, иначе поток навернется и память потечет рекой.... Label тоже его может вызвать.,. Массив для работы с потоками тоже не лучший вариант я об об этом узнал правда только сегодня днем.. TObjectList ок вариант, точнее наследник от него. Длинные/много строчные комментарии лучше писать так. {Комент.... Комент,..} Ну и ты не написал о том что это абстрактный класс и от него всегда надо наследоваца. Цитата:
А память то не освобождаеца.... Это самая большая ошибка, неофиты врятли ее увидят. И будут думать после нных запусков куда делась память??? |
Цитата:
"Директива Private начинает раздел данных (полей) и подпрограмм (методы) класса, которые являются частными (внутренними) для этого класса." |
Цитата:
Цитата:
В размещении кода в одном юните я не вижу ничего страшного. А вот утечку памяти я не учёл, так как я уделил внимание именно потокам и организации их создания. Про массив тоже слышу первый раз. И пока не сталкивался с моментами в которых он работает нестабильно. Исключения я с удовольствием добавлю. Так же считаю, что пора завязывать с этим спором, так как каждый будет стоять на своём. |
Цитата:
Код:
SimpleClass = classКод:
varЕсли все это объявлено в одном юните. |
а не проще & лучше вместо TThread юзать апи потоки? (beginthread - createthread)
|
Цитата:
С BeginThread для прямой передачи данных надо описывать свой тип передавать в него данные... Я пользовался сначала BeginThread когда попробовал TThread(научился с ним работать), до этого я не вьежал как переопределить метод и многово не понимал... Я потом окуел сколько я тратил времени на создание потоков через BeginThread...(В плане велосипедов для передачи данных в поток ) Сча вот пишу компонент чтоб кинул на форму, указатели на форму и нужные классы дал и готово.. И самое главное использование TThread это ООП стиль программирования(если вся программа в нем написана), а BeginThread\CreatThread Функциональный\процедурны (я различие обоих стилей не знаю(функц.проц.)). Ну и это опять же увеличение повторного использования кода. Вместо BeginThread(Параметры); Я зделаю, Thread := TThread.Create(замороженный\не замороженный); Конечно можно выполнить создание через макросы, но как по мне целесообразней юзать TThread для десктоп софта, не для ботов и.т.д. |
| Время: 08:30 |