Threading в Делфи е ужасен дявол, както той е боядисан


Threading в Делфи: това е ужасна дявол, както той е боядисан?

Threading в Делфи: това е ужасна дявол, както той е боядисан?

Често се вижда на становището на форуми, които потоците не са необходими на всички, всяка програма може да бъде написано така, че той ще работи добре без тях. Разбира се, ако не се направи нещо по-сериозно "Hello World" е вярно, но ако постепенно се натрупа опит, рано или късно, всеки начинаещ програмист отпочинали възможността на "плосък" код, е необходимо да паралелизация задачи. Някои задачи, които не може да се реализира на всички без използването на конци, например работата с контакти, на COM-порт, отдавна чакам за всякакви събития и т.н.

Всеки знае, че Windows е многозадачност. Просто казано, това означава, че все повече програми могат да работят едновременно върху операционната система. Всичко, което отваря Task Manager и да видите списък на процеси. Процесът - пример за прилагането на движение. В действителност, само по себе си не изпълнява, той е създаден, когато приложението се стартира, се съдържа информация, чрез който системата работи с него, така че той се отпусне необходимата памет за код и данни. За да се направи програмата да работи, той е създаден в потока. Всеки процес, съдържа поне една нишка, и тя е отговорна за изпълнението на код и получава времето на процесора. Това се постига и въображаемите паралелни работни програми, или както я наричат, псевдо. Защо е въображаемо? Да, защото всъщност процесора във всеки един момент може да носи само една част от кода. Windows разпределя процесорното време за всички теми, в системата, един по един, като по този начин изглежда, че те работят по едно и също време. Действителни потоци, паралелно работещи могат да бъдат само на машини с две или повече процесори.

За да създадете допълнителни теми в Делфи има базов клас TThread а. от него ще бъде наследен в изпълнението на потоците си. С цел да се създаде "скелет" на нов клас, можете да изберете File меню - Нов - Тема на обекта, Delphi ще създаде нов модул с детайла в своя клас. Аз ще го опиша за представяне в модула за форма. Както можете да видите в този прибирането на реколтата добавя един метод - Изпълнение. Това е всичко, и ние трябва да замените кода вътре в нея и тя ще работи в отделна нишка. И така, нека да напишем един пример - тече в безкраен цикъл на потока:

Стартирайте проба за извършване и кликнете. Изглежда, нищо не се случва - формата не е обесен, реагира на движение. В действителност това не е така - отидете на диспечера на задачите и ще видите, че процесора е заредена напълно. Сега в процеса на вашето приложение, което работи на две теми - едната е създадена Първоначално, когато се стартира приложението. Вторият, който ще се изпращат като процесор - ние създадохме с натискането на един бутон. Така че, нека да видим, какво прави кода в Button1Click:

NewThread: = TNewThread.Create (истина); тук ние сме създали инстанция на TNewThread. Създаване на конструктор има само един вариант - CreateSuspended тип булев, което показва, започнете нова тема веднага след създаването (ако невярно), или да изчака команда (ако е вярно). New.FreeOnTerminate: = вярно; FreeOnTerminate имот се посочва, че потока след края автоматично, обектът ще бъде унищожен и ние няма да се наложи да го унищожи ръчно. В нашия пример, това няма значение, защото само по себе си никога няма да бъде завършен, но ще са необходими в следните примери. NewThread.Priority: = tpLower; Приоритет собственост, ако все още не сте се досетили от името, определя приоритета на конеца. Да, да, всеки конец в системата има свой приоритет. Ако времето за процесор не е достатъчно, системата започва да го разпространява според поток приоритет. Приоритет имот може да отнеме от следните стойности:
  • tpTimeCritical - критична
  • tpHighest - много висок
  • tpHigher - високо
  • tpNormal - Междинно
  • tpLower - Ниска
  • tpLowest - много ниска
  • tpIdle - поток бягане през системата на времето на престой
Насочете висок приоритет поток не е необходимо, освен ако не се изисква от задачата, тъй като това е тежък товар върху системата. NewThread.Resume; Ами, всъщност, потокът започва.

Мисля, че сега разбирате как се създават нишки. Забележка, нищо сложно. Но не всичко е толкова просто. Тя ще изглежда - напишете код, в метода на Execute, и всичко, и никакви потоци имат една неприятна имот - те не знаят нищо един за друг. И какво от това? - Вие питате. Ето какво: да речем, че се опитват да променят потока от останалото имущество на всеки компонент във формуляра. Както е известно, на VCL единично влизане, всички от кода в рамките на приложението се изпълнява последователно. Така например, в процеса на който и да е променил данните в рамките на класове VCL, системата избира момента основният поток преминава около други потоци и се връща обратно, изпълнението на код продължава от точката, в която в застой. Ако сме от тяхната промяна поток нещо, например, във формата, участва в много механизми VCL (Напомням ви, от основния поток сега "е спрян"), съответно, през това време ще има време да промените каквито и да било данни. Изведнъж време се дава на основния поток отново, той тихо продължава изпълнението му, но данните се е променило! За това, което може да доведе - това е невъзможно да се предскаже. Можете да го проверите хиляди пъти и нищо не се случва, а от програмата хиляди и първа ще се срине. Това се отнася не само за взаимодействие с основния поток по-нататък, но също и за взаимодействие между потоците. Напиши като ненадеждни програма, разбира се, е невъзможно.

Тук стигаме до един много важен въпрос - синхронизиране на конеца.

Сега ProgressBar ходове, и това е напълно безопасно. Сигурно затова: Синхронизиране на процедурата в момента на спиране на изпълнението на нашия поток, и предава управлението на основния поток, т.е. SetProgress екзекутиран в основната нишка. Необходимо е да се помни, защото някои правят грешки, извършване вътре Синхронизиране дългосрочна работа, в този случай, очевидно, под формата замръзва за дълго време. Затова използвайте Синхронизиране за показване на информация - същите dviganie компоненти за актуализация напредък заглавни и т.н.

Може би сте забелязали, че ние използваме процеса на съня в цикъла. В единична резба Sleep приложение се използва рядко, но поток е много удобен за използване. Пример - безкраен цикъл, докато не се направи някакво състояние. Ако не поставите да спите ние просто натоварване на системата безполезна работа.

Надявам се да се разбере как работи Синхронизиране. Но има и друг доста лесен начин за прехвърляне на информация форма - изпращане на съобщение. Нека да разгледаме това, както добре. За да направите това, ние заявяваме, постоянно:

Сега имаме малко промяна, можете да се опрости дори казват, прилагането на метода на Execute нашия поток:

С помощта на функцията SendMessage, ние изпращаме прозорец заявление съобщение, един от които съдържа параметрите, които искате от нас да прогресира. Едно съобщение се нарежда на опашка, и в съответствие с това на опашката ще бъдат обработвани от основната нишка, където методът се изпълнява SetProgressPos. Но има една уговорка: SendMessage, какъвто е случаят с Синхронизиране, спира изпълнението на нашия поток, а основната нишка не обработва съобщението. Ако използвате PostMessage това не се случи, ние ще изпратим на потока от съобщения и ще продължи работата си, и само тогава, когато тя се обработва там - това няма значение. Кои от тези функции да се използва - вие решавате, че всичко зависи от задачата.

Тук по принцип ние обхванати основните начини на работа с компонентите на нишката VCL. И какво, ако нашата програма не е нова тема, но няколко? И ние трябва да се организира работата с едни и същи данни? Тук стигаме до другите методи за синхронизация за помощ. Един от тях ние смятаме. За да го изпълни, ще трябва да добавите към модула за SyncObjs проекта.

Най-интересният начин, по мое мнение - критичните участъци

Те работят както следва: само една нишка, а другият чака завършването му може да работи вътре в критична точка. За да се разбере по-добре всички са направени сравнения с тесен тръба, представете си, от една страна "тълпата" потоци, но тръбата може да "се изкачи" единственият, и когато "се измъкне сам" - започва втората част, и така в ред. Даже по-лесно да се разбере това с един пример, и също ProgressBar'om. Така че, тече един от примера, даден по-рано. Кликнете върху бутона, изчакайте няколко секунди и след това натиснете отново. Какво става? ProgressBar започна да скочи. Скок, защото ние използваме повече от един поток, но две, и всеки от тях предава различни значения напредък. Сега малко се преработи кода в форми onCreate събитието ще създаде критична точка:

Имаме две TCriticalSection имаме нужда от метод, при влизане и излизане, съответно, в и извън нея. Ние поставяме нашия код в критична точка:

Опитайте се да стартирате приложението и натиснете бутона няколко пъти, а след това се преброи колко пъти ще се напредък. Ясно е, че това, което е същността? Първият път, когато натискате бутона, ние създаваме поток, отнема критична точка, и започва да работи. Натиснете втория - втората нишка се създава, но критичната част е заета, и той чака, докато го освобождава първия. Трето, четвърто - всичко минава само на опашката.

Критичните участъци са много подходящи за приложение при обработката на едни и същи данни (списъци, решетки), от различни нишки. С разбирането как те работят, винаги може да намери приложение за тях.

В тази малка статия не покриват всички методи за синхронизация, има събития (TEvent), както и система за обекти като mutexes (Mutex), семафори (семафор), но те са по-подходящи за комуникация между приложения. Останалата, по отношение на класа на използване TThread, можете да научите сами по себе си, в HELP'e всичко доста подробно. Целта на тази статия - за да се покаже начинаещи, това не е толкова трудно и страшно нещо, за да разбера какво е това. И много практика - най-важното нещо е преживяване!