A szinkronizálás folyamata és módszerei delphiben, különböző cikkekben, cikkekben, programozásban -
Az alkalmazás indításakor a rendszer automatikusan létrehoz egy szálat a végrehajtásához. Ezért, ha az alkalmazás egyszálú, akkor minden kódot egymás után hajtanak végre, figyelembe véve az összes feltételes és feltétel nélküli átmenetet.
A multithreading több program pszeudo-párhuzamos működését biztosítja. Bizonyos esetekben a szálak létrehozása nélkül nem tehetõ meg, például blokkoló módban a foglalatok használata esetén.
A delphi-ban van egy speciális osztály, amely a szálakat - tthread-et hajtja végre. Ez az alap osztály, amelyből örökölni kell az osztályodat, és felül kell hagynia a végrehajtási módszert.
Most már kódot írhat a tnew.execute eljárás testébe, a program végrehajtására.
Finom pillanat. Az eljárás testében nem kell az ősök módszerét hívni.
Most el kell kezdened a szálat. Mint minden új osztály, meg kell teremteni:
A létrehozási módszerben érvényes érték azt jelenti, hogy az osztály létrehozása után a szál nem fog automatikusan elindulni.
Ezután meghatároztuk, hogy az áramlási kód befejezése után azonnal befejeződik, azaz nem érdekel a zárás. Ellenkező esetben meg kell hívnia a befejezési funkciót.
Állítsa a prioritást az egyik lehetséges értékre:
tpidle Működik, ha a rendszer tétlen
A legalacsonyabb tplowest
tplower alacsony
tpnormális Normál
tphigher Magas
legmagasabb
tptimecritical Critical
Nem ajánlom túl magas prioritást. a szál jelentősen betöltheti a rendszert.
Finom pillanat. Ha a folyamatban egy végtelen számú folyamat zajlik, akkor a szál betölti a rendszert a string alatt. Ennek elkerülése érdekében helyezze be az alvás (n) funkciót, ahol n az ezredmásodpercek száma, amelyre a szál megáll, amikor találkozik ezzel a funkcióval. n a megoldandó probléma függvényében kell kiválasztani.
Egyébként, ha az áramlási kódot külön modulban kívánja írni, kicsit leegyszerűsítheti az osztály csontvázát. Ehhez válassza ki az objektumtárban lévő szál objektumot (Ez az új lapon található). Megjelenik egy ablak, amelyben meg kell adnia az osztály nevét, majd az OK gomb megnyomásával automatikusan létrejön egy új modul az osztályának vázával.
Szálak szinkronizálása az vcl összetevők elérésekor
Tehát megtudtuk, hogyan lehet szálakat létrehozni. De akkor egy érdekes dolog felbukkan: mi történik, ha két szál ugyanazokra az adatokra utal? Például két szál megpróbálja megváltoztatni a fő űrlap fejlécét.
Különösen erre a célra szinkronizáló mechanizmusokat alkalmaznak az operációs rendszerben. Különösen a klasszikus tthread-ben van egy olyan módszer, amely lehetővé teszi a párhuzamos hozzáférést a vcl-komponensekhez:
eljárás szinkronizálása (módszer: tthreadmethod);
Itt egy teljes példa, amelyben az addstr módszer néhány sort ad hozzá a memo-hoz. Ha csak a módszert hívjuk, akkor a patakok sorai véletlenszerű sorrendbe kerülnek. Ha az addstr szinkronizálásra kerül, akkor a sorokat először egy szálból, majd a másodikból kell hozzáadni. Kiderül, hogy a szál kizárólag rögzíti az erőforrás memo, és hozzá a szükséges információkat, miután hozzáadta a szál kiadja a jegyzetet, és most egy másik szál lehet felvenni a jegyzetet a jegyzetet. Kevesebb szó - nagyobb bizalom:
felhasználások
ablakok, üzenetek, rendszerek, változatok, osztályok, grafikák, vezérlések, formák, párbeszédek, stdctrls;
tnew = osztály (tthread)
magán
s: string;
eljárás addstr;
védett
az eljárás végrehajtása; felülbírálhatja;
végén;
var
1. forma: tform 1;
new1, new2: tnew;
eljárás tform 1.button1click (sender: tobject);
kezdődik
new1: = tnew.create (igaz);
new1.freeonterminate: = igaz;
new1.s: = '1 téma';
new1.priority: = tplowest;
new2: = tnew.create (igaz);
new2.freeonterminate: = true;
new2.s: = '2 téma';
new2.priority: = tptimecritical;
new1.resume;
new2.resume;
végén;
eljárás tnew.execute;
kezdődik
szinkronizál (addstr); // Hívja a módszert szinkronizálással
// addstr; // A módszer szinkronizálás nélküli hívása
végén;
A szinkronizálás egyéb módjai. A syncobj modul
A syncobj modulban vannak szinkronizációs osztályok, amelyek az api függvényhívások csomagolásai. Összesen öt osztályt jelöltek ki ebben a modulban. a tcriticalsection, a tevent, valamint a tevent-tsimpleevent osztály egyszerűbb végrehajtása, és szálak szinkronizálására használják, a többi osztályt nem lehet figyelembe venni. Itt van a modul hierarchiája:
A kritikus szakaszok a tritikus szekcióban
A legegyszerűbb megértés a kritikus szakasz vagy a kritikus szakasz. A kritikus szakaszban található kód csak egy szálon hajtható végre. Elvileg a kódot nem osztják ki, hanem a kritikus szakaszon keresztül hívják a kódot. A kód elején a rész bevitelének és a szakaszból való kilépésnek a funkciója van. Ha a szakaszt egy másik szál foglalja el, a szálak várakoznak, amíg a kritikus szakasz felszabadul.
A munka elején létre kell hozni a kritikus szakaszt:
var
szakasz: tritikus szekció; // globális változó
kezdődik
section.create;
végén;
Tegyük fel, hogy létezik egy olyan függvény, amelyben elemeket adunk a globális tömbhöz:
Tegyük fel, hogy több szál hívja ezt a funkciót, így az adatkonfliktus elkerülése érdekében a kritikus részt a következőképpen használhatja:
függvény addelem (i: integer);
var
n: egész szám;
kezdődik
section.enter;
n: = hossza (mas);
setlength (mas, n + 1);
mas [n + 1]: = i;
section.leave;
végén;
Megmondom, hogy több kritikus szakasz is lehet. Ezért, ha olyan funkciót használ, amelyekben adatkonfliktus léphet fel, minden funkciónak saját kritikus szakaszt kell létrehoznia. Használatuk befejezése után, amikor a funkciókat már nem hívják, a szakaszokat el kell pusztítani.
Amint azt Ön is megértette, nagyon remélem, hogy a kritikus rész bejárata és kilépése nem kell egyetlen funkcióban lennie. A bejegyzés csak azt jelöli, hogy egy másik szál találkozik a bemenettel és megtalálja a büszkeségét. És a kimenet egyszerűen felszabadítja a bemenetet. Egyszerűen, a kritikus szakasz csak egy csatorna keskeny csöveként jelenhet meg, amint az áramlás a csőhöz közeledik, belenéz, és ha látja, hogy valaki már átmegy a csőben, akkor várni fogja, amíg a másik ki nem jön.
És itt egy példa, amelyben egy elemet hozzáadunk egy dinamikus tömbhöz. Az alvó funkció késleltetést ad a huroknak, amely lehetővé teszi, hogy vizuálisan megnézze az adatokkal való ütközést, ha természetesen eltávolítja a bevitelt és a kimenetet a kód kritikus szakaszából.
felhasználások
ablakok, üzenetek, rendszerek, változatok, osztályok, grafikák, kontrollok, formák, dialógusok, stdctrls, syncobjs;
típus
tform 1 = osztály (tform)
gomb1: gomb;
memo1: tmemo;
űrlap létrehozása (sender: tobject);
az eljárási forma megsemmisül (feladó: tobject);
procedúra button1click (sender: tobject);
magán
nyilvános
végén;
tnew = osztály (tthread)
védett
az eljárás végrehajtása; felülbírálhatja;
végén;
var
1. forma: tform 1;
cs: tcriticalsection;
new1, new2: tnew;
mas: tömb egész;
eljárás tform 1.form létrehozása (sender: tobject);
kezdődik
setlength (mas, 1);
mas [0]: = 6;
// Hozzon létre egy kritikus részt
cs: = tcriticalsection.create;
végén;
eljárás tform 1.form elpusztítani (sender: tobject);
kezdődik
// Törölje a kritikus részt
cs.free;
végén;
eljárás tform 1.button1click (sender: tobject);
kezdődik
new1: = tnew.create (igaz);
new1.freeonterminate: = igaz;
new1.priority: = tpidle;
new2: = tnew.create (igaz);
new2.freeonterminate: = true;
new2.priority: = tptimecritical;
new1.resume;
new2.resume;
végén;
Kezdetektől fogva, nem sok a várakozási funkciókról. Ezek olyan funkciók, amelyek felfüggesztik a menet végrehajtását. A várakoztatási funkció egy konkrét esete az alvás, mint érv, az ezredmásodpercek száma, amelyre be szeretné fagyni vagy szüneteltetni a streamet.
Finom pillanat. Ha az alvás (0) hívásra kerül, akkor a szál elhagyja az órai ciklust - a processzor idejét, és azonnal bejut a sorba, ha hajlandó végrehajtani.
A teljes várakozási funkció a szálleírások (ok) paramétereként kerül átadásra. Most nem foglalkozom velük részletesen. Elvileg a várakozó funkciók egyes szinkronizációs osztályokat tartalmaznak explicit formában, a többiek nem kifejezetten.
A Tevent események nem csak egy többszálú alkalmazásban, hanem egyetlen szálként is használhatók, mint a kódszakaszok közötti koordináció és az adatok egy alkalmazásból egy másikba történő átvitele. Többszálú alkalmazásoknál a tevent használata ésszerűbbé és érthetőbbé válik.
Minden a következőképpen történik. Ha az esemény be van állítva, akkor lehetséges tovább dolgozni, ha az esemény visszaáll, majd minden más szál vár. Az események és a kritikus szakaszok közötti különbség az, hogy az eseményeket a szál kódjában ellenőrizzük, és a várakozási funkciót kifejezetten használjuk. Ha a várakozó funkciót a kritikus szakaszban automatikusan végrehajtották, akkor az események használatakor szükség van arra, hogy lehívja a streamet.
Az események automatikus visszaállítással és automatikus visszaállítás nélkül történnek. Az autoset segítségével ez azt jelenti, hogy az esemény azonnal visszaáll a várakozó funkcióból való visszatérés után. Ha az eseményeket az automatikus visszaállítás nélkül használja, akkor azokat vissza kell állítania.
Az automatikus visszaállítás nélküli esemény hasznos a szüneteltetéshez az áramláskód bizonyos pontján. Ha csak szünetet tartasz a patakban, ha nem számít, hol jelenik meg a fagyás, használhatja a tthread.suspend módszert. Az automatikus visszaállítással rendelkező események, valamint a kritikus szakaszok használhatók.
Az indításhoz egy eseményt kell létrehozni, és lehetőleg az azokat használó szálak létrehozása előtt, bár pontosabb a várakozási funkció hívása.
create (esemény attribútumok: psecurityattributes; manualreset, initialstate: boolean; const name: string);
eventattributes - nullát.
manualreset - auto reset - hamis, auto reset nélkül - igaz.
initialstate - kezdeti állapot true - set, false - reset.
const név az esemény neve, üresen állítva. A folyamatok közötti adatcsere során egy névvel rendelkező eseményre van szükség.
var
esemény: tevent;
new1, new2: tnew; // streamek
...
kezdődik
esemény: = tevent.create (nulla, hamis, hamis, '');
végén;
eljárás tnew.execute;
var
n: egész szám;
kezdődik
event.waitfor (végtelen);
n: = hossza (mas);
setlength (mas, n + 1);
mas [n + 1]: = i;
event.setevent;
végén;
Most már nincsenek hibák.
A legkönnyebb használni a tsimpleevent osztály, amely a tevent örököse, és csak abban különbözik attól, hogy a konstruktor azonnal felhívja az őse építőjét a beállított paraméterekkel:
create (nil, true, false, '');
Valójában a tsimpleevent egy esemény, amelynek nincsen automatikus visszaállítása, reset állapotban és név nélkül.
A következő példa bemutatja, hogyan kell felfüggeszteni a szálat egy bizonyos helyen végrehajtani. Ebben a példában három előrehaladási sáv található az űrlapon, a téma betölti a progressbar-t. Ha szükséges, szüneteltetheti és folytathatja a progressbar-t. Ahogyan megérted, létrehozunk egy eseményt automatikus visszaállítás nélkül. Bár célszerűbb a tsimpleevent használata, akkor a tevent-t használtuk, mert a munka megértése a tevent-el egyszerűen egyszerűen megy.
felhasználások
ablakok, üzenetek, rendszerek, változatok, osztályok, grafikák, kontrollok, formák, párbeszédek, stdctrls, syncobjs, comctrls;
típus
tform 1 = osztály (tform)
gomb1: gomb;
progressbar1: tprogressbar;
progressbar2: tprogressbar;
progressbar3: tprogressbar;
gomb2: tbutton;
űrlap létrehozása (sender: tobject);
az eljárási forma megsemmisül (feladó: tobject);
procedúra button1click (sender: tobject);
procedúra button2click (sender: tobject);
magán
nyilvános
végén;
tnew = osztály (tthread)
védett
az eljárás végrehajtása; felülbírálhatja;
végén;
var
1. forma: tform 1;
új: tnew;
esemény: tevent;
eljárás tform 1.form létrehozása (sender: tobject);
kezdődik
// Hozzon létre egy eseményt mielőtt használnánk
esemény: = tevent.create (nulla, igaz, igaz, '');
Indítsa el a szálat
új: = tnew.create (true);
new.freeonterminate: = igaz;
new.priority: = tplowest;
new.resume;
végén;
eljárás tform 1.form elpusztítani (sender: tobject);
kezdődik
// Törli az eseményt
event.free;
végén;
eljárás tnew.execute;
var
n: egész szám;
kezdődik
n: = 0;
míg igaz
kezdődik
// wait függvény
event.waitfor (végtelen);
ha n> 99 akkor
n: = 0;
// Egyidejűleg növekszik
formája 1.progressbar1.position: = n;
formája 1.progressbar2.position: = n;
formája 1.progressbar3.position: = n;
// a láthatóság késleltetése
alvás (100);
inc (n)
végén;
végén;
eljárás tform 1.button1click (sender: tobject);
kezdődik
// Állítsa be az eseményt
// wait függvény azonnal visszavezeti a vezérlést
event.setevent;
végén;
eljárás tform 1.button2click (sender: tobject);
kezdődik
// wait függvény blokkolja az áramlási kód végrehajtását
event.resetevent;
végén;
Az automatikus visszaállítás eseményének egy példája a két szál munkája, és a következők szerint működik. Egy adat készíti az adatokat, és egy másik tételt, miután az adatok készen vannak, például elküldi őket a kiszolgálónak vagy bárhol. Kiderül valami, mint egy sorozatos munka.
felhasználások
ablakok, üzenetek, rendszerek, változatok, osztályok, grafikák, kontrollok, formák, párbeszédek, stdctrls, syncobjs, comctrls;
tproc = osztály (tthread)
védett
az eljárás végrehajtása; felülbírálhatja;
végén;
tsend = osztály (tthread)
védett
az eljárás végrehajtása; felülbírálhatja;
végén;
var
1. forma: tform 1;
proc: tproc;
küldés: tsend;
esemény: tevent;
eljárás tform 1.form létrehozása (sender: tobject);
kezdődik
// Hozzon létre egy eseményt mielőtt használnánk
esemény: = tevent.create (nulla, hamis, igaz, '');
Indítsa el a szálakat
proc: = tproc.create (igaz);
proc.freeonterminate: = igaz;
proc.priority: = tplowest;
proc.resume;
küldés: = tsend. létre (igaz);
küldeni. freeonterminate: = igaz;
küldeni. prioritás: = tplowest;
küldeni. folytatásához;
végén;
eljárás tform 1.form elpusztítani (sender: tobject);
kezdődik
// Törli az eseményt
event.free;
végén;
Ez az összes szinkronizációs objektum, a syncobjs modul, amely elvben elég különböző problémák megoldására. Az ablakokban vannak más szinkronizációs objektumok is, amelyek a delphi-ban is használhatók, de már az api szinten. Ezek mutex mutexek, szemafores szemaforok és várható időzítők.