Net-Base Maġazin

24.07.2026

Delphi: TParallel.For b'Progress-UI threadsigura (TThread.Queue) mingħajr deadlocks

Kif tikkombina Delphi TParallel.For ma' UI tal-progress sigura għall-threads: aġġornamenti permezz ta' TThread.Queue, aggregazzjoni nadifa, maniġġjar tal-kanċellazzjoni u sitwazzjonijiet tipiċi ta' deadlock fid-debugging u fil-operazzjoni.

24.07.2026

Minn suġġett tar-rivista għall-prattika tal-proġett

Paġni ta' servizz u paġni tekniċi relevanti għall-artiklu

Min fil-Delphi jixtieq jparalellizza kompiti b’ħafna kalkolu jew b’ħafna I/O, jispiċċa malajr fuq il-Parallel Programming Library (PPL) u speċifikament fuq TParallel.For. Ir-riżultat huwa spiss viżibbli immedjatament – sakemm fil-istess mument trid aġġorna b’mod «malajr» UI tal-progress. Hawn jiġru l-iffriżar tipiku: UI-freezes f’apparenza każwali, ProgressBar li taqbeż lura, jew deadlock komplet, ladarba tkun qed tmur pass pass fil-debugger.

F’dan l-artiklu nitkellmu dwar Progress-UI threadsikura għal TParallel.For: mudell robust li jaħdem kemm f’VCL kif ukoll f’FMX, li jikkonċentra b’mod nadif l-aġġornamenti tal-UI permezz ta’ TThread.Queue, jikkunsidra Cancel/Abort u jevita b’mod konsekuttiv il-falli ewlenin li jwasslu għal deadlock. Il-fokus hu fuq il-realità ta’ xogħol: mġieba riproduċibbli, responsabbiltajiet ċari u suġġerimenti għad-debug li jgħinuk anki meta l-iżball jinqala’ biss «bei Kunden».

Għaliex il-Progress-UI spiss tinqala’ problemi ma’ TParallel.For

TParallel.For normalment jitħaddem fuq worker-threads mill-pool tat-thread ta’ Delphi. Dawn it-threads m’għandhomx jmissu direkt kontrolli VCL jew FMX, għax il-frameworks tal-UI (Message Loop, Window Handles, Rendering) huma marbuta mar-thread prinċipali. Anki kumment aparentement innocwu bħal ProgressBar.Position := … minn worker jista’ jwassal għal mġieba indefinita: AVs sporadiċi, twieqi mqaxxra jew aġġornamenti li “jifdaw”.

Ir-rimedju ovvju ħafna drabi hu TThread.Synchronize. Dan jissolva l-kwistjoni tal-thread-safety, iżda f’loop-paralleli jwassal malajr għal problema oħra: jinħoloq biċċa bottleneck serjali. Kull worker jistenna lill-thread prinċipali, li min-naħa tiegħu huwa mgħobbi bil-rendering u bil-proporzjon ta’ sejħiet Synchronize. Fuq tagħbija tidher bħal deadlock – anki jekk fil-fatt hu effett ta’ starvation/lockstep.

U mbagħad hemm il-klassi reali tad-deadlock: il-thread prinċipali jistenna (eż. permezz ta’ WaitFor, Task.Wait jew indirettament permezz ta’ sejħiet li jwaqqfuk) sa jtemm l-operazzjoni parallela, filwaqt li l-worker-threads jippruvaw jibagħtu xogħol lill-thread prinċipali permezz ta’ Synchronize jew permezz ta’ użu inapproprjat ta’ Queue. Ir-riżultat: il-thread prinċipali jistenna għall-workers u l-workers jistennew għall-thread prinċipali.

TThread.Queue vs. TThread.Synchronize: der praktische Unterschied

Unschärfer Debugger-Blick mit Notizen zu Threads und Queue als Kontext für Queue vs Synchronize
Fil-debugging tara malajr jekk il-worker-threads qed jistennew għall-thread prinċipali jew sempliċiment qed ipoġġu aġġornamenti fil-Queue.

Iż-żewġ mekanismi jintużaw biex kodiċi jitħaddem b’mod sigur fil-thread prinċipali. Id-differenza hi fis-semantika tal-istennija:

  • TThread.Synchronize: il-worker li sejjaħ jistenna sakemm il-thread prinċipali jimplimenta l-kodiċi. Dan hu “synchron”, iżid latenzi u huwa ingredjent klassiku għal deadlocks meta l-thread prinċipali jkun imblukkat.
  • TThread.Queue: Il-worker jpoġġi l-kodiċi biss f’kju għall-thread ewlieni u jkompli jaħdem. Dan hu „asinkronu“, jiddekupla l-Threads u huwa kważi dejjem l-għażla default aħjar f’sitwazzjonijiet paralleli – sakemm tiġi kkontrollata l-frekwenza tal-aġġornamenti.

Importanti: Queue mhix permess libere. Jekk tibgħat aġġornament tal-Queue f’kull iterazzjoni ta‘ ċiklu, tgħaddas il-Queue tal-thread ewlieni. Allura l-UI mhux se tkun fil-«deadlock», iżda tibqa‘ taħdem bil-mod minħabba n-numru kbir ta‘ messaġġi. Il-UI tidher «tqila», u t-tmiem tal-ipproċessar jintefa‘ lura għax għad fadal mijiet jew eluf ta‘ aġġornamenti tal-UI li għadhom jiġi eżegwiti.

Il-każ estrem li verament jagħmel ħsara: stennija fil-thread tal-UI

F’applikazzjonijiet korporattivi spiss naraw dan il-fluss: ikklikkja fuq il-buttuna „Start“, il-UI tinħall, ProgressDialog jiftaħ, u mbagħad jistenna sinċronament sakemm kollox jintemm, u wara jerġa‘ jattiva. Dan il-mudell huwa l-qalba ta‘ ħafna deadlocks.

Varjanti tipiċi (skond il-bażi tal-kodiċi):

  • Il-thread ewlieni jibda TParallel.For u sussegwentement jsejjaħ loġika ta‘ stennija li tibbloċka (direttament jew indirettament).
  • ProgressDialog jsejjaħ fil-Constructor jew OnShow rutina li internament tistenna.
  • Buttuna ta‘ Annulla tissettja flag, iżda l-thread ewlieni jibqa‘ katschat f’ċiklu ta‘ stennija.

Jekk il-worker-Threads jużaw f’dan il-perjodu Synchronize, deadlock huwa prattikament garantiti. Anke bil-Queue jista‘ jkun hemm qabbad jekk il-thread ewlieni jibqa‘ jibbloċka u ma jipproċessax messaġġi – għaliex allura lanqas il-Queue ma tiġi eżegwita.

Il-konsegwenza operazzjonali hija: il-thread ewlieni m’għandux jibbloċka jistenna għall-loop parallelu jekk huma meħtieġa aġġornamenti tal-UI parallelament. Minflok, il-proċess għandu jkun jew kollu mgħoddi f’task ta‘ sfond, jew trid torganizza tmiem asinkronu (callback/queued azzjoni ta‘ tlestija) li jerġa‘ jippermetti lill-UI fl-aħħar.

Aproċċ nadif: Progress biss aggregat, aġġornamenti tal-UI mnaqqsa

Motiv tal-post tax-xogħol bi displayer ta' progress astratt u kejl ta' żmien bħala simbolu għal aġġornamenti tal-UI mnaqqsa
L-aggregazzjoni u d-drosseljar ibbażat fuq iż-żmien jipprevjenu li l-UI tkun mgħottija b’aktar aġġornamenti milli meħtieġ.

Mudell robust jikkonsisti f’tlett responsabbiltajiet ċar u separati:

  • Worker-Threads jagħmlu x-xogħol reali għal kull element/index. Irreportjaw biss il-progress f’forma sigura għat-Threads (kontatur, Queue, Thread-safe Queue).
  • Aggregator (spiss: il-thread ewlieni jew timer dedikat fil-UI) jikkalkula minn dak il-progress status għall-UI (pożizzjoni, test, ETA) u jaġġorna l-controls. B’dan tevita aġġornamenti 1:1 għal kull iterazzjoni.
  • Konklużjoni (wkoll fil-thread ewlieni): tirrestawra l-UI, turi r-riżultat, tissummarizza l-iżbalji u tirrilaxxa r-riżorsi.

Għaliex din id-diviżjoni taħdem daqstant tajjeb: il-workload jista’ jkun ta’ frekwenza għolja (eluf ta’ elementi), imma l-UI teħtieġ biss ftit aġġornamenti kull sekonda. Fil-prattika biżżejjed 5–10 aġġornamenti/s, u f’impjiegi ħafna mgħaġġla anke 2–4. Kollox ’il fuq minn hekk spiss hu biss storbju viżiv u jikkonsma ħin CPU fil-Message Pump.

Ċensiment threadsigur: Atomiku minflok Lock

Għal ProgressBar sempliċi ħafna drabi jaqbel kontar atomiku. “Atomiku” ifisser: l-inkrement u r-read iseħħu mingħajr Race Condition, tipikament permezz ta’ TInterlocked. B’dan tevita Locks (Critical Sections) fil-hot path tal-loop.

Ideja minima ippruvata:

  • Il-kwantità totali tkun magħrufa minn qabel (eż. numru rekord, fajls, IDs).
  • Kull iterazzjoni iżżid b’mod atomiku DoneCounter.
  • Timer tal-UI jaqra l-counter periodikament u jissettja ProgressBar.Position.

Vantaġġ: L-ebda TThread.Queue għal kull element, l-ebda saturazzjoni tal-UI. Żvantaġġ: m’għandekx messaġġi dettaljati għal kull element (eż. isem fajl). Tista’ żżid messaġġ ta’ status sekondarju u mdawwar għal dik il-funzjonalità (ara l-sezzjoni li jmiss).

Messaġġi ta’ status mingħajr spam: “l-aħħar status jirbaħ”

Jekk trid turi wkoll test qasir (element attwali, fazi, ħtija), għandek bżonn mudell li ma jaffundax l-UI b’kull pass tal-worker. Fil-prattika jaħdem tajjeb il-prinċipju “l-aħħar status jirbaħ”:

  • Il-worker jikteb informazzjoni ta’ status f’setup threadsigur (eż. string li jista’ jiġi skambjat b’mod atomiku, jew protett b’lock żgħir).
  • Timer tal-UI jieħu periodikament l-aħħar status viżibbli u jpoġġih f’label.

B’hekk il-UI tibqa’ reattiva u xorta tara li qed jiġri xi ħaġa. Importanti hawn mhux tant is-string innifsu imma l-perjodu tal-ħajja: evita li tieħu referenzi għal oġġetti temporanji mill-worker-threads u tgħaddi l-istess referenzi lill-UI-thread. Jekk tgħaddi oġġetti, spjega l-proprjetà b’mod espliċitu.

TParallel.For threadsigura Progress-UI bil TThread.Queue: mudell robust

Hemm xenarji fejn timer tal-UI waħdu mhu jaqbilx: eż. meta trid kunfidenza li fil-aħħar tħaddem eżatt wieħed “Done”-update, jew meta l-aġġornament tal-UI hu pass iktar kumpless (eż. insert f’materjal tal-log, imma mdawwar). F’dak il-każ TThread.Queue jista’ jkun xieraq – imma mhux għal kull iterazzjoni, imma b’mod mirati.

Approċċ prattiku hu Queue biss għal eventi b’frekwenza baxxa:

  • Start-Event (ipprepara l-UI, ibblokka l-buttuni)
  • Eventi ta’ progress periodiċi (massimu kull X millisekonda)
  • Eventi ta’ żball (opsjonali, miġbura)
  • Done-Event (irrestawra l-UI, uri r-riżultat)

Il-periodiċità m’għandhiex issir fuq l-UI-thread, iżda diġà fil-kuntest tal-worker: ħalli l-worker jidħol fil-queue biss meta minn tal-aħħar aġġornament tal-UI passa biżżejjed żmien. Għal dan tuża sors ta’ żmien monotonu (eż. TickCount) flimkien ma’ valur atomiku ta’ “last update”.

Importanti: l-aġġornament tal-UI għandu jkun “malajr”. Kalkuli tqil, I/O fuq fajls jew aċċessi għall-bażi ta’ data m’għandhomx ikunu fil-callback tal-UI li jkun ġie mqiegħed fil-queue. Il-callback għandu biss jaqra stati u jissettja controls.

Ħarsien tal-kansellazzjoni: Ikkanċella mingħajr tfixkil

F’applikazzjonijiet reali il-kansellazzjoni mhix fakultattiva. Deċiżjonijiet: Cancel mhuwiex “kill”, imma tmiem kooperattiv. Il-workers għandhom jevalwaw b’mod regolari jekk is-sinjal ta’ kansellazzjoni ġie mċaqlaq u mbagħad joħorġu b’mod nadif. F’Delphi hemm diversi modi għal dan (skont il-kostruzzjoni PPL): flag Volatile proprju, boolean atomiku, jew kunċett ta’ Cancellation permezz ta’ Tasks (skont il-verżjoni u l-arkitettura ta’ Delphi).

Għal l-operat hemm żewġ regoli importanti:

  • Il-buttuna Cancel trid tkun viżibbli malajr: Iċċekkja l-flag ta‘ kansellazzjoni f’postijiet raġonevoli, mhux biss fl-aħħar ta‘ iterazzjoni, speċjalment meta l-iterazzjoni tista‘ tieħu sekondi.
  • Cancel għandu jneħħi r-riżorsi: Handles miftuħa, fajls temporanji, transazzjonijiet jew locks m’għandhomx jibqgħu. Dan ifisser: F’kull iterazzjoni tal-Worker huma obbligatorji blokki try/finally meta r-riżorsi huma involuti.

Min-naħa tal-UI, Cancel għandu biss jissettja sinjal u jpoġġi l-UI f’status „Stopping…“. Il-konklużjoni vera u r-riattivazzjoni tal-UI iseħħu fil-Done-Event, mhux immedjatament waqt il-klik.

Evita deadlocks: die häufigsten Fallen in der Praxis

Diagramm eines zyklischen Wartens zwischen Threads als Visualisierung eines Deadlocks
Deadlocks spiss jiġru minħabba stennija ċiklika: il-UI-Thread jiġi blukat, il-Worker jistennew aċċess għall-UI.

Trappola 1: WaitFor/Task.Wait im Main Thread

Meta l-Main Thread ikun blukat, ma jistax jeżegwixxi callbacks ta‘ Queue u ma jproċessa l-messages. Dan jidher bħal deadlock, anke jekk il-Worker jkomplu b’mod korrett. Soluzzjoni: l-ebda waits li jibbloġġjaw fil-UI-Thread. Minflok, poġġi l-azzjoni ta‘ konklużjoni permezz ta‘ TThread.Queue jew kontroll b’event (eż. timer jiċċekkja „lesta“).

Trappola 2: Synchronize innerhalb eines Locks

Klassika: Worker iżomm Critical Section, imbagħad iċempel Synchronize, u fil-UI-callback (direttament jew indirettament) ikun meħtieġ lura l-istess Critical Section. Riżultat: ċirku ta‘ stennija. Ir-regola hija sempliċi: Ebda pass tal-UI (Synchronize/Queue) minn ġewwa lock imżomm. Jekk lock hu meħtieġ, kopja d-dejta kollha f’variabbli lokali, ħalli l-lock, u mbagħad poġġi l-operazzjoni fil-queue.

Trappola 3: UI-Callback jiġġenera reentrancy

Xi drabi l-aġġornament tal-UI innifsu mhuwiex „ħelu“: l-issettjar ta‘ Properties jista‘ jħajjar Events (OnChange, OnResize), li jwasslu għal loġika li taċċessa stati tal-Worker. Dan mhux deadlock fil-aktar sens strett, iżda jwassal għal hangs diffiċli biex tispjega u għal Race Conditions. Soluzzjoni: poġġi l-aġġornamenti tal-UI f’pathijiet “kwieti” (ddiżattiva l-Events temporanjament) jew uża reentrancy-guards (eż. guard atomiku għall-fażi ta‘ aġġornament).

Trappola 4: Zu viele queued Updates

Anke mingħajr Waits il-UI tista‘ „twaqaf“ jekk toħloq għexieren ta‘ eluf ta‘ callbacks mqassma. Sintomi: il-ProgressBar tkompli timbotta ‚il quddiem għal żmien twil, it-tieqa tirreaġixxi bil-mod, u l-CPU fil-Main Thread tkun għolja. Soluzzjoni: tnaqqis tal-velocità (finestra taż-żmien), aggregazzjoni (kontatur), jew struttura verament Producer/Consumer, fejn biss aġġornament wieħed tal-UI jista‘ jkun pending (Coalescing).

Meta jsir aktar kumpless: jiġbor riżultati, jippakkja żbalji, jiggarantixxi ordnijiet

TParallel.For huwa ideali meta l-iterazzjonijiet huma indipendenti. Fil-software tan-negozju l-iterazzjonijiet spiss huma biss „b’mod wiesgħa“ indipendenti: taqraw fajls, sejħu REST-APIs, tikteb ringieli fil-bażi tad-dejta. F’dak il-każ għandek bżonn tippjana sew tliet punti addizzjonali:

  • Ġbir ta‘ riżultati li hu thread-sigurtà: Jew per thread buffer lokali (u fl-aħħar jingħaqdu) jew Queue/Collection thread-sigura. Evita locks fil-hot path.
  • Immaniġġjar tal-eċċezzjonijiet: l-eċċezzjonijiet mill-Worker-Threads għandhom jiġu miġbura. Fil-prattika jservi tajjeb: iżomm l-ewwel eċċezzjoni u jattiva l-Cancel, jew jiġbor il-kollezzjoni ta‘ eċċezzjonijiet u jurihom flimkien fl-aħħar.
  • Ordni: Jekk l-output jeħtieġ ordni stabbli (pereżempju logs skont indiċi), il-proċessar parallelu b’sortjar sussegwenti spiss ikun aktar sempliċi mill-„inseriment ordinat thread-safe“.

Għall-UI dan ifisser: ma turi każ ta‘ żball immedjatament. Dan iwassal għal infern ta‘ dialogi modali. Iġbor l-iżbalji (pereżempju lista ta‘ stringi) u urihom fl-aħħar bħala sommarju jew log esportabbli.

Debugging: Kif tagħmel id-deadlock tassew viżibbli

Deadlocks fil-kodiċi parallelu huma frustrazzjoni għax jistgħu jidhru differenti fid-debugger meta mqabbla mar-release. Madankollu hemm ċerti leveri prattiċi:

Uża t-tieqa tal-Threads u l-Call Stacks

Jekk l-UI tistagna, eżamina l-ħjut kollha: fejn qiegħed il-Main Thread? Qed jistenna? Huwa f’message-loop? Fejn qegħdin il-Worker-Threads? Jekk il-Worker huma staggmati f‘Synchronize, il-kawża kważi dejjem tkun „Main Thread imblukkat“ jew „Main Thread jeħtieġ Lock“.

Marka l-punti tal-Queue/Synchronize

Poġġi logging mirqum fil-punti ta‘ trasferiment (qabel il-Queue, fil-Queue-callback, fit-tmiem tal-iterazzjoni). Fil-produzzjoni dan spiss ikun aktar prezzjuż mill-breakpoints, għax il-timing huwa deċiżiv. Żgura li l-logging innifsu jkun thread-safe u non-blocking (per eżempju, ebda output tal-log għall-UI direttament mill-Worker-Threads).

Imkejjel il-ħin tal-last-update

Jekk l-UI „tistagna“, jista‘ jkun sempliċement li għandha wisq aġġornamenti biex tipproċessa. Għalhekk imkejjel fil-Main Thread kemm drabi fis-sekonda twettaq UI-update u kemm idum. Ladarba l-UI-callbacks jieħdu aktar minn ftit millisekondi, għandek bżonn throttling jew semplifikazzjoni.

Kemm hu utli TParallel.For b’Progress-UI verament?

Il-parallelizzazione mhix skop għalih innifsu. Tibbenefika speċjalment meta:

  • l-iterazzjonijiet huma biżżejjed kbar (millisekondi sa sekondi) sabiex l-overhead tal-threadpool jiġi assorbit,
  • ix-xogħol huwa intensiv fuq il-CPU (Parsing, kompressjoni, Hashing) jew għandu I/O faċilment parallelizzabbli (diversi fajls, diversi HTTP-Requests b’limiti),
  • għandek strateġija ċara għall-Cancel u għall-maniġġjar tal-iżbalji,
  • ir-rekwiżiti tal-UI jistgħu jingħataw b’progress aggregat.

Tibbenefika inqas meta kull iterazzjoni tkun estremament qasira (mikro-operazzjonijiet) jew meta l-iterazzjonijiet kollha joperaw fuq l-istess punt ta‘ strozzatura (transazzjoni DB seriali, lock globali, fajl wieħed). F’dak il-każ, l-intervent aktar mgħaġġel spiss ikun: ittejjeb l-algoritmu, uża batch processing, tnaqqas l-aċċess tad-dejta jew iddikoppja espliċitament il-punt ta‘ strozzatura.

Checklista tal-prattika: Kif tibqa‘ l-UI stabbli

  • Main Thread mhux imblukkat: ebda waits, ebda loops twal mingħajr message pump.
  • Il-Worker qatt ma jikkontrollaw il-controls: ebda access VCL/FMX barra mill-UI-Threads.
  • UI-updates huma throttled: uża counter/timer jew coalesced Queue-updates minflok kull iterazzjoni.
  • Ebda chiamata Synchronize minn ġewwa locks.
  • Il-Cancel huwa kooperattiv, jiġi kkontrollat spiss u jagħmel tindif nadif.
  • L-eċċezzjonijiet jiġu miġbura u jiġu pproċessati b’mod ordnat fl-aħħar.

Konklużjoni: Iddekoppelja fil-Queue, stabbilizza bl-aggregazzjoni

UI ta‘ progress robusta f‘TParallel.For ma tinħolqx billi tpoġġi „Synchronize“ xi mkien, iżda permezz ta‘ prinċipju ta‘ arkitettura ċar: il-Worker jaħdmu b’mod indipendenti, il-Main Thread jibqa‘ ħieles u jipproċessa biss ftit u mgħaġġla aġġornamenti tal-UI. TThread.Queue huwa l-għodda t-tajba jekk tużah b’mod mmirat u b’kontroll tal-frekwenza. Għal mġieba „bil-mod“ jew instabbli huma kważi dejjem responsabbli żewġ kawżi: il-Main Thread jistenna b’mod li jibbloċka f’post wieħed – jew jinġeraq f’ħafna aġġornamenti mqiegħda fil-queue.

Meta issettja l-mudell b’mod nadif (Counter/Coalescing, Cancel-Flag, callback tat-tlestija), jiswa li jintuża f’ħafna partijiet ta‘ applikazzjoni Delphi żviluppata maż-żmien: Import/Export, verifiki tad-dejta, kompiti ta‘ fajl u tal-API – kollox isir aktar reattiv mingħajr ma toħloq deadlocks ġodda għal kull aġġornament tal-progress.

Jekk għandek bżonn appoġġ biex tistabbilizza kodiċi parallelu, biex tdebuggja problemi ta‘ freeze tal-UI jew biex timmodernizza b’mod nadif applikazzjonijiet Delphi mibnija maż-żmien: ikkuntattjana.

Għal dan it-tema huma importanti wkoll Delphi Parallel Programming Library u Tthread.queue Vs Synchronize. Il-kariga tpoġġi dawn l-aspett f’kuntest b’mod ċar u turi x’hu rilevanti fil-prattika ta‘ kuljum.

Tiddiskuti proġett jew inizjattiva ta‘ modernizzazzjoni ma‘ Net-Base.

Pass li jmiss

Meta suġġett jiġi mwettaq bħala proġett reali, l-arkitettura, is-sistema eżistenti u l-operat għandhom jiġu kkunsidrati flimkien kmieni.

Aħna nappoġġjaw mhux biss f'kwistjonijiet puntwali, iżda wkoll meta biċċiet ta' kodiċi sors, temi legacy jew ideat għal portali jridu jsiru proġett korporattiv stabbli u affidabbli.

  • L-istat attwali, l-istat tal-mira u r-riskji tekniċi jiġu vvalutati flimkien.
  • REST, aċċess tad-dejta, portalijiet u rollout ma jiġu posposti bħala konsegwenzi tardivi.
  • Tara kmieni liema triq hija ekonomika u operattivament sostenibbli.

Aqsam il-post

Aqsam dan il-post direttament

LinkedIn, X, XING, Facebook, WhatsApp u E-Mail huma disponibbli immedjatament. Għal Instagram nippreparaw il-link u test qasir direttament.

Imejl

Instagram jiftaħ f'tab ġdid. Il-link u t-test qasir jiġu kkopjati qabel fil-clipboard.