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

Wenn aus dem Thema ein reales Projekt wird, sollten Architektur, Bestand und Betrieb früh zusammen betrachtet werden.

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, Datenzugriff, Portale und Rollout werden nicht als Spätfolgen verschoben.
  • Sie sehen früh, welcher Weg wirtschaftlich und betrieblich tragfähig ist.

Aqsam il-post

Aqsam dan il-post direttament

LinkedIn, X, XING, Facebook, WhatsApp und E-Mail sind sofort verfügbar. für Instagram bereiten wir Link und Kurztext direkt vor.

Imejl

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