Példa egy egyszerű többszálú hálózati szerver fejlesztésére 5. rész
Ez a tartalom a sorozat része: Példa egy egyszerű többszálú hálózati kiszolgáló kifejlesztésére
Vigyázz az új cikkekre ebben a sorozatban.
Miután ismerkedtünk a ciklus előző részében a TCP-n keresztüli hálózati kapcsolatok megszervezésével, logikus gondolkodni a program válaszában a hálózati kérésekre. A technológiai megközelítések kialakulásának jelenlegi szakaszában, mint általában, néhány, amely lehetővé teszi számunkra, hogy olyan rugalmas programokat hozzunk létre, amelyek jó arányban állnak a tervezett felhasználással és terheléssel. Hagyományosan nincs jobb megközelítés, minden esetben releváns. A bejövő kérelmekre adott válaszok elérhető módjai kombinálhatók például a következő listában:
- "csak" feldolgozza az aktuális kérést, és visszatér egy új kérés várakozásához;
- generál egy új folyamatot, és átadja neki a kérést; visszatérés a várakozáshoz;
- generál egy új végrehajtási menet (thread) és elküldi a kérés feldolgozását; visszatérés a várakozáshoz;
- lehetőség van arra, hogy több folyamatot vagy szálat előállítsunk előre, és tartsuk őket "párologtatva", és amikor megkérjük, hogy feldolgozzuk az egyiket, és visszatérjünk a várakozásokhoz;
- akkor tetszőleges folyamatáram-kombinációkat használhat, amelyekben több folyamatot generál, amelyek több szálat tartalmaznak.
Egyszerű feldolgozás
A legegyszerűbb megoldás az, hogy nem generál semmit, hanem feldolgozza a kérést annak a folyamatnak (vagy szálnak), amelyet a kérések várnak. A programozás szempontjából a megközelítés rendkívül egyszerű, de mint sok egyszerű, rugalmatlan és kevéssé komoly terhelés.
Ha a kérelmek gyakrabban jönnek el, mint a programnak ideje feldolgozni őket, akkor meg kell várniuk a sorrendet. Ha a kérések várakozási ideje hosszabb, mint valami érték, akkor a rendszermag újra elutasítja a beérkező kéréseket. Egyértelmű, hogy egy egyprocesszoros rendszer egy egymagos processzor párhuzamosítását feldolgozása generáló folyamat / szál képes radikálisan javítani a helyzeten, mivel processzor, így szinte mindig elfoglalt a program kódja. Mindazonáltal a jelenléte a többmagos processzor és / vagy többprocesszoros rendszer a különbség az egyszerű feldolgozás és párhuzamosított nem lesz mellette egy egyszerű megoldás, mert ebben az esetben lesz intenzíven használt csak egy processzor (vagy egymagos), és az összes többi lesz tétlen.
multi-folyamat kezelés
Ebben az esetben a kérés beérkezése után új folyamatot generál (amely a kérelemben megkapott aktuális folyamat egy példánya), amelyen a feldolgozás történik. Ez például így történik (itt csak egy lehetséges megközelítés illusztrációja):
A villa (2) funkcióval új folyamatot generálunk. Ebben az esetben nincs szükség kifejezetten átadni valamit a gyermeknek, mert az ívás pillanatában a gyermek a szülő egy példánya (a kapcsolatleírások "szorzása"). Miután sikeresen ívtál egy gyermeket, bezárhatja az új kapcsolatot a szülő kontextusában, és visszatérhet a következőhöz. Ezt megelőzően, összefüggésben a szülő áll, mint valamit, hogy emlékezzen az azonosítóját (PID) a gyermek folyamat később, annak befejezését követően, ez az azonosító lehet eltávolítani információk véget leszármazottja folyamatok az asztal elkerülése érdekében túlzsúfoltság neki istálló és hogy a tevékenységek a init rendszer folyamat. Mennyire tudjuk pontosan az utódok befejezését?
Ha az állam a gyermek folyamat (felfüggesztett, folytatják, vagy befejezte) küld egy szülő mag SIGCHLD jel lehet összefüggésben feldolgozott alapanyag, és megteszi a szükséges lépéseket. Ennek a jelnek a feldolgozásához explicit módon szerepelnie kell, mert alapértelmezés szerint figyelmen kívül hagyja. A jel érkezésekor futtathatja a mentett pid leszármazottak listáját minden egyes hívásnál, például a waitpid (2) függvényben a nonblocking módban, és nézze meg az eredményt. Ezt elkerülheti, ha a felsorolás lista a gyermekek szülei (befejezése előtt) pid ez leszármazottja bármely, a módszerek IPC (Inter Process Communication) - csatorna (cső), a socket fájlt vagy razdelyamuyu memóriát. Ebben az esetben van egy "lehetőség" arra, hogy egyszerre több párat kapjunk, mivel több leszármazotta szinte egyidejű befejezése következtében több jel is "összeolvad". Azonban, ha alkalmazásod egyszerre fut, sok leszármazotthoz hasonlóan, akkor még egy ilyen "batch" elfogadás is előnyösebb, ha a jel minden előfordulására teljes listát sorol fel. A folyamatok párhuzamos feldolgozásának mellékhatása a folyamatok relatív függetlensége a folyamatok között, mivel mindegyik folyamatnak saját elszigetelt memóriahelye van és saját hibái vannak. Mindez azt jelenti, hogy az egyik folyamat kritikus hibája általában nem vezet az egész program összeomlásához. Attól függően, hogy a preferenciák és a tapasztalat az izolációs memória folyamatok lehetnek mínusz, mert hála ez a folyamat kezdetben nincs közös változók vagy néhány adatstruktúrák és az információcsere közöttük kell gyakorolni extra erőfeszítést szervezni azt az IPC módszerekkel. Ez szükségessé teszi a figyelmet és a szinkronizálást (az "írók" és "olvasók" problémájának megkerülése), így az ilyen információcsere nem romlik. Egy egyszerű megoldás erre a problémára lehet a csövek használata, de ezeknek is vannak korlátai. A legtermékenyebb a jelentős mennyiségű (több száz kilobájt vagy több) olyan nem-szinkron adatcsere osztott memóriát, de azzal a feltétellel, hogy az adatok által használt tárolási helyét, anélkül, hogy további példányt a megosztott memória valahol máshol, és ez gondos és pontos tervezés és valószínűleg bonyolítja az alkalmazást.
Többszálas feldolgozás
Jelenleg a GNU / Linuxban a szálak különbözőek a folyamatoktól, főként egy tulajdonságkészletben és olyan dolgokban, mint a családi execve (2), exec (3) hívófunkciói az egyik szálon. Ie és a folyamatok és a szálak a rendszermag-ütemező objektumainak ütemezése, függetlenül blokkolhatók, fogadhatnak jeleket stb. Sőt, még a gyermek folyamat és áramlás alakul ki hasonló módon, a klón funkció (2) felsorolja az érintett zászlók, amelyek meghatározzák a tulajdonságait generált objektum (részletek megtalálhatók a kézikönyvben az ezt a funkciót).
Mindazonáltal ezek még mindig egy konkrét megvalósítás részleteit, és a folyamatok és folyamatok közötti kapcsolat ugyanaz maradt:
A bejövő összeköttetésre például reagálhat például egy patak generálásával (ez szintén illusztráció, nem teljes kód):
A pthread_create (3) segítségével létrehoz egy új végrehajtási tételt, amely, ha sikeres, elhelyezi a létrehozott szál azonosítóját a memóriában a threadId mutatóban. A pthread_create (3) függvény egyik argumentuma (a void * típusnak) ahhoz, hogy átadjon valamit a stream függvénynek (ami a téma kezdetének pontja). Egy változót (pl. Az esetünkben az új csatlakozással rendelkező aljzatleírót) átadhatunk, először kifejezetten a void * típushoz vezetjük, majd a fordított függvényt már a stream funkcióban is elvégezzük. Ha valamilyen blokkot (például "heterogén" adatokat) szeretne átvinni, akkor a blokkhoz tartozó mutató ugyanazt a kétszeres explicit leadet ad át.
Többszálú programozás egy jó gyakorlat a paraméter, mivel általában kimutatható az összes szükséges külső adatfolyam együtt egy egységes szerkezetű, amely tele előtt áramlását, és egy mutató egy olyan termék, amely azután, hogy az áramlás irányát, mint egy érv funkciót. Ennek köszönhetően a belépési pont a patak gyakran az egyetlen adatpont ez a téma (kivéve a minimális összeg, amit néhány globális adatok) közvetlenül vagy közvetve (pointerek), amely hasznos lehet az egyszerűség kedvéért és a rend.
A globális hatókör általában olyan adatokat tartalmaz, amelyek mindegyike egyszerre szükséges, és amelyeket nem kell megváltoztatni, vagy olyan adatokat, amelyek a szálak közötti csere tárgyát képezik. Global tárgyak is kijelenthetjük mutexek és a szemafor, de ez valószínűleg nagyban meghatározza a személyes preferencia - használjak a munkát nekik „beszélő” nevek és általában nyilvánították a globális környezetben.
Különben meg kell állnunk az áramlás végén. Ebben az összefüggésben a szálak kétféle lehetnek - csatolva (csatolt) és nem csatolva (leválasztva, leválasztva, stb. Leválasztva). Első eszköze áramlás nagyjából ugyanaz, mint a folyamat - befejezése után flow-szülő gyermeke kell „laikus” mögötte útján pthread_join (3) függvényt, ami kell tárolni, és folyam ID (threadid a példában). Ha nem érdekel a visszatérő ág függvény értékének, vagy nem vissza semmit, akkor létrehozhat egy adatfolyam azonnal megszakad, és utána nem lesz akadálya annak, hogy a rendszer, és ennek megfelelően tölteni a források.
A többszálú alkalmazások fejlesztésében fontos pont a folyamatokban megnevezett funkciók menetbiztonsága: biztonság vagy megbízhatóság egy funkció végrehajtása során ugyanazon folyamat több szálának kontextusában. Ezt például a fent említett kritikus szakasz és / vagy más módszerek segítségével érhetjük el:
- povtornovhodimost (újra entrancy): Az általános esetben lehetetlen megjósolni, hogyan fog tervezni a munkafolyamatokat és a kernel szál ütemező (milyen sorrendben, milyen időben), és előfordulhat, hogy egy szál felfüggesztésre kerül végrehajtása során a kód bizonyos funkciók és menedzsment egy másik szálra kerül, amely ugyanazt a funkciót hajtja végre, majd visszaadja a felfüggesztett szálat. Ismételhetőek azok a funkciók, amikor olyan kódot hajt végre, amelynek szálai nem észlelnek ilyen "helyettesítést". Másrészt a nem eredeti funkciók "tényezõ tényezõként" használhatók (bár nem 100% -os válasz esetén). Ismételhetőség csak lokális változók alkalmazásával érhető el, és a változás globális változóival való munkavégzés nélkül is megvalósítható.
- Helyi tárolás: mielőtt megkezdené az összes szükséges adat feldolgozását az áramlás összefüggésében, először másolatokat kell készíteni helyi változókra az átfolyási függvénynek, amely minden egyes téma sajátja.
- atombicitás: számos olyan művelet létezik, amelyekben a kernel folyamatosságot garantál, azaz ha elindulnak, akkor szükségszerűen a felfüggesztés nélkül, a jelenlegi szál kontextusában befejeződnek; Ezek általában elemi műveletek, mint a növekmény / csökkenés.
Process-stream kombinációk
Az unió a két fent említett módszerek, általában kerüli a termelési folyamat a vízfolyások - miért van szükség egy példányt a folyamat egy csomó nem a saját dolog folyik? Ehelyett, vagy az összes szükséges folyamatokat előre létrehozzuk, hogy hozzon létre vegyületek és generáló stream vagy generált „időpontok között”, mint szükséges (például olyan halasztott töltési folyamat árrés „párolt”, amikor kimerült) egy külön, „példakénti” és / vagy a "tiszta" folyamat. Egy ilyen megközelítés indokolt esetekben, amikor a töltött idő a termelési folyamat vagy szál feldolgozására vegyület alapvető fontosságú, és azt kell a lehető legkisebbre csökkenteni. A programok kidolgozása meglehetősen nehéz feladat, főleg azért, mert annak szükségességét, hogy gondosan mérlegelje, és létrehozza inter-process-szál és interakció. Ott is szükségessé teszi az egyes belső parancsokat és / vagy eljárások egy rugalmasabb és szabályozható közötti kölcsönhatás folyamatok és szálak magukat.
következtetés
Egy vegyes megközelítés alkalmazható, ha szükséges egyesíteni mindkét említett opciót egy alkalmazásban.
A cikk nem említi az áramlások törlésének kérdését sem. Ráadásul ez a rész - másokhoz hasonlóan - még mindig jelentős önálló munkát jelent.
Források letöltése
Kapcsolódó témák
- Példa egy egyszerű, többszálú hálózati kiszolgáló kifejlesztésére, amely támogatja a C munkameneteket a GNU / Linuxban: 1. rész. Ismerje meg a fejlesztői környezetet. A parancssori paraméterek elemzése, a beépített segítség támogatása, a program "demonizálása".
- Példa egy egyszerű, többszálú hálózati kiszolgáló kifejlesztésére, amely támogatja a GNU / Linux operációs rendszer C nyelvű felhasználói munkameneteit: 2. rész A parancssor paramétereinek átfogó elemzése.
- Egy példa a fejlesztés egy egyszerű többszálú webkiszolgáló, amely támogatja a felhasználói munkamenetek a C nyelvben az operációs rendszer GNU / Linux: 3. rész Munka a konfigurációs fájl inicializálni a belső struktúrák a program.
- Példa egy egyszerű, többszálú hálózati kiszolgáló fejlesztésére, amely támogatja a C munkameneteket a GNU / Linuxban: 4. rész A hálózati kapcsolatokra alkalmazott I / O technikák áttekintése.
- Példa egy egyszerű, többszálú hálózati kiszolgáló kifejlesztésére a C munkamenetek GNU / Linux operációs rendszerben történő támogatásával: 5. rész A hálózati kérelmek (folyamatok, szálak és ezek kombinációi) párhuzamos feldolgozásának módszerei.
- Példa egy egyszerű, többszálú hálózati kiszolgáló fejlesztésére a GNU / Linux operációs rendszerben a C munkamenetek támogatásához: 6. rész: Hitelesítési mechanizmusok.