prog. elmélet, egy thread v. több

prog. elmélet, egy thread v. több
2003-05-29T09:42:31+02:00
2003-06-17T11:56:22+02:00
2022-11-02T04:20:39+01:00
  • Igyvan, ha vmi mas is blokkol, ami gondot okozhat, termeszetesen hamar szuksegesse valhat a dolog.

    Az egy v. tobb thread eseti kerdes, tehat nem igazan dontheto el altalanossagban. Recept adhato, de kivetelek mindig akadnak.

    Sokan gondolom felnek a thread-ektol, pedig nem nagyon kell, csak el kell kezdeni hasznalni oket. Par gubanc utan rajon az ember mire kell vigyazni.

    Amugy a temahoz kapcsolodo cikk:
    http://www.codeproject.com/threads/sync.asp
    Erdemes elolvasni.
    Mutasd a teljes hozzászólást!
  • Ha az én konkrét feladatomra gondolsz, akkor a valóban igényelte a multithread-et.

    A leírásomból igazából nem derült ki, de a probléma elég bonyolult tulajdonképpen, és csak az egyik alapvető probléma az, hogy a hardver eseményeinek olvasása a beérkezett esemény (ez pl. egy gomb megnyomása, mely lehet akár 5 perc múlva is) blokkolja az olvasási funkciót... Tehát többek közt emiatt kellett a thread-eket alkalmazni.
    Mutasd a teljes hozzászólást!
  • Izé... szerintem nem a procinak adod át az ütemezést, hanem a kernelnek.

    Ok, botlas volt.

    1. nem biztos, hogy okosabb tudsz lenni, mint a scheduler

    Nem is all szandekomban. A konkret feladat szerintem nem igenyelte szalak letrehozasat. Inkabb csak plusz koltsegeket generalt, errol probaltam szollani.

    2. Tuti, hogy meggátoltad azt, hogy esetleges többprocis rendszeren normálisan fusson a kód.

    Az adott service ideje nagy reszet wait fuggvenyekben tolti. Nem hiszem, hogy csokkenti a hatekonysagat, ha n db helyett 1 db thread var egy db wait fuggvenyben.

    Igen, mint irtam az MT sok esetben jo dolog. Az adott esetben en nem ezt valasztanam, csupan ennyit probaltam megfogalmazni.
    Mutasd a teljes hozzászólást!
  • Nincs hozza remote debugger?


    Delphihez? De, van.

    En szinten in-process COM-ot gyartok eppen


    Ez out-of-process, in-service (azaz egy Windows Service-ben implementált) (D)COM server. Elsősorban azért ilyen a kialakítás, hogy minél egyszerűbben kapjunk egy hatékony threading és IPC megoldást (itt a kliens és a szerver mindig egyetlen gépen van).

    Gyakorlatilag tényleg nincs szükségem IDE debuggerre, megszoktam a debug output-alapú debuggolást, összetettebb kódot pedig egyébként is megéri külön projectben tesztelni mielőtt becsekkelné az ember a főprojectbe. Arról nem is beszélve, hogy ez rákényszerít a modularizációra, ami hosszú távon kifizetődő.

    Péter
    Mutasd a teljes hozzászólást!
  • A procin meg mindig csak egy process futhat egyszerre (eltekintve a HT-tol :). Tehat a MT programot hasznalsz, akkor igazabol atadod az utemezest a procinak.


    Izé... szerintem nem a procinak adod át az ütemezést, hanem a kernelnek. Aki egyébként eddig is ezt csinálta.

    Ha olyan a probléma, akkor jól megtervezett MT megoldással segítesz a kernelnek, hogy optimálisan adagolja a processzort (pl. nem ciklusban várakozol, hogy valami nagyon triviálisat mondjak -- bár többprocesszoros rendszerben meg van, hogy pont az a jó ;). Ha saját magad írod meg MT nélkül, akkor

    1. nem biztos, hogy okosabb tudsz lenni, mint a scheduler (viszont az se biztos, hogy tudsz jó MT kódot tervezni)

    2. Tuti, hogy meggátoltad azt, hogy esetleges többprocis rendszeren normálisan fusson a kód.
    Mutasd a teljes hozzászólást!
  • Nincs hozza remote debugger?

    En szinten in-process COM-ot gyartok eppen, de Pythonban. Ehhez van egy jo remote debugger (Komodo) ami elegge megkonnyiti az ember eletet.

    netchan
    Mutasd a teljes hozzászólást!
  • Mi most kinlodunk rendesen linux-on a MT programok debuggolasaval. A gdb nincs a helyzet magaslatan.


    Nem tudom, ki hogy van vele, de IMHO a multithread alkalmazások debuggolása mindig is szivás volt.

    Részemről az egyik központi project egy in-service COM serverként van megvalósítva, amit talán épp lehetne Delphiből debuggolni, de nem lenne valami egyszerű, úgyhogy nem is tudom mikor helyeztem el breakpointot ebben a kódban.

    Ezért lehetőség szerint minden beépítendő kódot külön projectben tesztelek, valamint a lehető legértékesebb NT multithread debugger eszközt használom és ez az OutputDebugString(). A debug console üzeneteket a Sysinterals DebugView-al (psdk dbgmon) elkapom és így máris pontosan elegendő debug információval rendelkezem.

    Péter
    Mutasd a teljes hozzászólást!
  • Ugyan ez nem zárja még ki a Multi-s várakozást, de egyszerűbb volt.


    Nekem ugy tunik, hogy "megsporoltal" egy wrapper class-t, azon az aron, hogy thread-eket hasznalsz.

    En szeretem a thread-eket, de csak akkor hasznalom oket, ha mashogy nem lehet valamit megcsinalni.

    Okok szoktak lenni a hasznalatra: vmi blokkol, vagy tul lassu; a tobb processzor altal nyujtott plusz teljesitmeny kell.

    Egy valamit nem art elfeledni. A procin meg mindig csak egy process futhat egyszerre (eltekintve a HT-tol :). Tehat a MT programot hasznalsz, akkor igazabol atadod az utemezest a procinak. Ez egy egy szalbol megoldhato feladatnal felesleges. (hisz igazabol csak plusz koltseg lesz, ami a szinkronizacio miatt kellhet)

    Mi most kinlodunk rendesen linux-on a MT programok debuggolasaval. A gdb nincs a helyzet magaslatan.
    Mutasd a teljes hozzászólást!
  • A fibereket "könnyűsúlyú szálakként" (lightweight thread) tartják számon, elvileg kisebb az overhead a használatuk során, de a scheduling a Te dolgod. Minden szálat lehet konvertálni fiberré.

    Az MSSQL úgy jön a képbe, hogy lehet választani, hogy fiber vagy thread-alapú legyen a szálmodell az MSSQL-ben.

    Igazából még nem láttam be, hogy olyan marha nagy előnye lenne a használatának.

    Az MSSQL-en kivül egy helyen hallottam, hogy használják/szeretnék használni, ez pedig az Indy Delphi/C++Builder network VCL, ahol már most is komoly teljesitményproblémákkal küzdenek (alapvetően tervezési hibák miatt).

    Péter
    Mutasd a teljes hozzászólást!
  • Context switch van, de a költsége változó. Ha a két thread (bejövő és kimenő) ugyanabban a process-ben van, akkor csak regisztereket kell váltani (fix és lebegőpontos, bár ez utóbbit lehet, hogy késleltetett módon végzi), stack-et kell cserélni (user és kernel módút is), meg el kell végezni a háztartási teendőket (pl. Perfmon counter update).

    Ha a thread-váltás egyben processzváltást is jelent, akkor drágább a dolog, mert a címteret is le kell cserélni. CR3 újratölt, page directory és page táblák frissülnek, ami ugye a TLB (Translation Look-aside Buffer) kipusztítását is jelenti, meg persze az L1, L2 cache tartalmainak várható újratöltögetését is.
    Mutasd a teljes hozzászólást!
  • Ezt en sem tudom, az viszont eleg altalanos velemeny, hogy a Windows szalkezelese nagyon hatekony, lehet, hogy pont emiatt.

    netchan
    Mutasd a teljes hozzászólást!
  • Nem vagyok benne biztos, hogy windows alatt a thread valtas CPU Context Switchinggel jar. Marpedig ha nem jar Context Swithinggel, akkor a thread valtas ugyanolyan gyors, mint a fibre valtas.
    Mutasd a teljes hozzászólást!
  • Szvsz nem furcsa. A jól megírt multithread (továbbiakban MT) alkalmazás pont elkerüli azt, amit kettővel lejjebb írsz: "ha sok thread van...", akkor ugye harcolnak az erőforrásokért, és szétverik a schedulert. Jó MT alkalmazás CPU-nként néhány thread-et hoz létre, és ezek között úgy osztja el a munkát (pl. közvetítő stack v. queue használatával), hogy a thread munkája kitöltse a rendelkezésre álló kvantumot. Ha így működik, akkor elég hasonlóan fog üzemelni a fiber/mikrothread alkalmazáshoz.

    Az idézet második fele arról szólhat (feltételes mód, mert én is csak olvastam valahol, személyes tapasztalatom nincs), hogy UNIX alatt a POSIX thread-ek (pthread) működött így (azaz kooperatív multitaszkolással), tehát ilyen alkalmazások Win32-re portolása lényegesebben egyszerű a fiber-ek használatával, mert így nem kell áttervezni az alkalmazást.
    Mutasd a teljes hozzászólást!
  • Igen, ugy fest ez az. Amit kicsit furcsallok:
    "In general, fibers do not provide advantages over a well-designed multithreaded application. However, using fibers can make it easier to port applications that were designed to schedule their own threads."

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wce..

    netchan
    Mutasd a teljes hozzászólást!
  • Köszi az infót!

    Még nem hallottam erről, de most utánanéztem egy picikét az MSDN-en.

    Windows alatt valóban fiber-nek hívják és API szinten van, úgy néz ki NT vonalon és 98+ on.

    Érdekességképpen: a "fiber" szóra köjön az SQL szerver thread felépítése, ha valakit érdekel.
    Mutasd a teljes hozzászólást!
  • Nem tudom, mi az a fiber, de magat a "mikorthread otlet" tobb nyelven is megvalosithato, ugyhogy lehet, hogy az az egyik implementacio neve. A lenyeg: "normalis" szalkezelessel akkor nyerunk sokat, ha az egyes szalak tobbfele eroforrast hasznalnak, mert ilyenkor lehet ugy valtogatni kozuluk, hogy a kulso esemenyre torteno varakozasok ne az aktiv futaskor tortenjenek. Magyarul, ha az A szal valami lemezmuveletre var, akkor addig a B szal CPU intenziv resze futtathato.

    Ha viszont sok szalad van, ami ugyanazt az eroforrast hasznalja (pl CPU), akkor gyakorlatilag csak bukta van a szalkezelesbol a nagy overhead miatt (kontext valtas, szemaforozas, kommunikacio). Ilyenkor jon kepbe a microthread, ami tulajodonkeppen a programon belul megvalositott "cooperativ multitasking". Ilyenkor a sajat programod reszeleti kozott "ugral" a vegrahajtas, ahol mindig az adott programreszlet donti el, hogy meddig az ove a CPU.
    Legegyszerubben egy peldan keresztul lehet atlatni a lenyeget:

    IBM Developer

    Ez pythonrol szol, de nem kell hozza pyton ismeret. Amit tudni kell az a "yield" kulcsszo: ez ugyanaz, mint a "return", tehat visszater a fuggvenybol, annyi kulonbseggel, hogy az adott fuggveny "allapota" megmarad, es a kovetkezo hivasnal a yield-tol folytatodik a kod. Pl ('def' a fuggvenydefiniciot jelzi):

    Pl ha a valami fuggveny igy nez ki:

    def valami():
    a=1
    yield a
    a+=1
    yield a
    a+=1
    yield a

    akkor az:

    fv=valami() #(itt a fuggveny mint objektum szerepel)
    fv.next()
    fv.next()
    fv.next()

    az 1,2,3 szamsort adja vissza.
    Kb ennyi :)
    Minden "szal" latja az egesz programot, tehat nem kell szopni a szalak kozotti kommunikacioval, stb. es nyilvan sokkal gazadasagosabb, hisz alig pazarol CPU idot.
    Ez az otlet csak nehany specialis helyzetben hasznalhato, de ott nagyon jol.

    Udv,
    netchan
    Mutasd a teljes hozzászólást!
  • Netchan,

    fiber-re gondolsz?
    Mutasd a teljes hozzászólást!
  • Mit értesz mikrothread alatt?
    Mutasd a teljes hozzászólást!
  • Meg az jutott eszembe, hogy ha ilyen csak CPU-t hasznalo szalak vannak, es nem kell multiprocesszor tamogatas, akkor nagyon jol johetnek a mikrothread-ek, mivel ezek az overhead-je csak toredeke (szazadresz talan) a rendes szalakenak.

    netchan
    Mutasd a teljes hozzászólást!
  • Igen. Ezért írtam azt, hogy megfontolandó :)


    Ez akkor lehet jó megoldás, ha a kiszolgálási idők azonosak és kellően rövidek, valamint a kérések száma nem változik túl dinamikusan.

    Szóval nem egyszerű a dolog. Az ideális algoritmus kiválasztásához feltétlen ismerni kell azt, hogy mi történik a folyamat kiszolgálása közben. Fontos dolog a legrövidebb/leghosszabb (!) és az átlagos kiszolgálási idő.

    Egy ilyen queue/stack esetén elég nagy problémák lehetnek, ha van a rendszernek egy lassú eleme. Ettől kamioneffektus fog kialakulni, és rossz esetben az egész szervert hazavágja, úgy, hogy az csak várakozni fog :)))
    Mutasd a teljes hozzászólást!
  • Ennel viszont vigyazni kell, nehogy "eheztetes" lepjen fel, mert a verem aljan levo elemik igy beragadhatnak.

    netchan
    Mutasd a teljes hozzászólást!
  • Bár, ha jobban belegondolok, akkor inkább

    LIFO (Last In First Out), de ez a lényegen nem változtat :)
    Mutasd a teljes hozzászólást!
  • Jogos, igen FILO-t akartam mondani. Köszi a javítást.
    Mutasd a teljes hozzászólást!
  • A QUEUE ugyan logikus választásnak tűnik (ugyebár a legelőször érkezett kerül elsőre kiszolgálásra), de megfontolandó a FIFO alkalmazása is


    Itt biznyára FILO (First In Last Out)-ra gondoltál és nem FIFO (First In First Out)-ra Bocsi a kekeckedésért
    Mutasd a teljes hozzászólást!
  • Hát a helyzet az, hogy több processzor esetén elég komplikált a dolog.

    A lényeg az, hogy ugyebár criticalsection-ok mindenképpen kelleni fognak, és a több thread között váltogatnod kellene.
    Egy-egy ilyen váltás pedig a processzoron content switch-et okoz, mely a cache teljes leürítését váltja ki és azt a procinak újra kell olvasnia a relatíve lassú memóriából...

    Tehát ha túl sokat vált a processzor thread-et, akkor gyakorlatilag a gép erőforrásait elpazarlod a cache újratöltésére :) És ez a jelenség a thread-ek számával kb. négyzetesen nő...


    Ezért érdemes lenne megfontolnod egy amolyan queue/fifo-s módszert. Tehát nem sok-sok thread-et futtatsz egyszerre, hanem a beérkező kéréseket egy-egy "várólistára fűzöd fel" és onnan veszed le egyenként.

    A QUEUE ugyan logikus választásnak tűnik (ugyebár a legelőször érkezett kerül elsőre kiszolgálásra), de megfontolandó a FIFO alkalmazása is! Ebben az esetben a kért adat nagy valószínüséggel még benne van a cache-ben, nem kell azt újra betölteni - esetleg már a "kilapozott" memóriaterületről netán page file-ból...


    Tehát ezeket a szempontokat át kellene gondolni alaposan. Összességében talán jobb megoldás processzoronként egy-egy thread-et alkalmazni, mint sokat, mert ez utóbbi rossz szervezés esetén akár lényegesen lassabb is lehet, mint 1 thread esetén.
    Mutasd a teljes hozzászólást!
  • Sziasztok

    Ennekem is thread problemaim vannak.

    Nalam ez az egesz kicsit mas, mert meg nem sikerult megcsinalnom ezt a threados dolgot, es masreszt azert is mert a programom inkabb szamitas igenyes, es threadokat a tobbprocis rendszerekhez kellene hasznalnom, a tobb processzor kihasznalasa vegett.

    Szoval ti ezt hogy csinalnatok??
    Mutasd a teljes hozzászólást!
  • Gondolom Kirilla-nak akartad címezni, hisz Ő írta.

    Én nem ismerem ilyen szinten a C-t, az általam vázolt megoldási lehetőségek inkább Delphi-re vonatkoztak.
    Mutasd a teljes hozzászólást!
  • mivel a ThreadFunctionom, jelenlegi tudásom szerint, nem lehet osztályfüggvény, így az csak a parméterként átadott osztályom publikus tagjaihoz fér hozzá


    Csak röviden:

    1. A thread-függvény lehetne pl. friend, ekkor direktben kezelheti az osztály privát tagjait is.

    Ennél jóval elegánsabb azonban a class static függvény alkalmazása:

    static DWORD WINAPI CTest::ThreadFunc(LPVOID lpParam)
    {
    }

    tagja az osztálynak, tehát hozzáfér a tagjaihoz. Static, tehát nem kell 'this' pointer a működéséhez, és a globál névteret sem szennyezi. A thread-től az objektumhoz mutató pointert meg lehet, hogy be tudod suvasztani TLS-be (Thread Local Storage).

    null
    Mutasd a teljes hozzászólást!
  • Ok. Köszi, mind a két megoldást kipróbálom és amelyik jobbnak néz ki azt fogom használni. Azért szeretnék minnél kevesebb globális és publikus tagot, mert azok úgy is elegen lesznek a szink. ( valószínű mutexet fogok használni ) és egyéb dolgok miatt és így átláthatalan lenne az egész.
    Mutasd a teljes hozzászólást!
  • "Én is azt szeretném, ha a Threadem és a "StopEvent" privátok lennének, de mivel a ThreadFunctionom, jelenlegi tudásom szerint, nem lehet osztályfüggvény, így az csak a parméterként átadott osztályom publikus tagjaihoz fér hozzá"

    Ebben az esetben két dolgot tehetsz:

    - Public-ba rakod az Event-et.
    - Magát az Event-re mutató pointert (is) átadod a thread-nek. Én ezt választottam, de nálam a thread konkrétan nem használja az objektumot.


    Ami a Count-ot illeti:

    Vigyázz vele, mert szinkronizálni kell! Nem teheted azt, hogy a thread-ból csak úgy növeled annak értékét és közben pl. egy timerrel frissited az user felületeden ezt a feliratot!


    Két megoldást látok:

    - Public-ba teszel egy-egy metódust, mely segítségével tudod írni/olvasni ezt az értéket. Ez védett blokkban lesz a szinkronizálás miatt.

    - Ugyanezt a metódust protected-be vagy private-ba teszed, és a thread forrását az osztállyal azonos fájlba teszed. Nem tudom, hogy ezt a C-ben meg lehet-e oldani? Delphi-ben megy a dolog. Lehet, hogy nem a legszebb, de ilyen esetben alkalmazható. Így mások számára láthatatlan lesz, de azért az azonos unitban lévő thread-ből simán eléred azt.

    De lehet, hogy C-ben ez másképp van, a Delphi simán megeszi.
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd