Thread, de hogyan?

Thread, de hogyan?
2019-06-06T11:52:33+02:00
2019-06-07T21:25:31+02:00
2022-12-06T00:41:54+01:00
Stella_209
Eddig mindig óckodtam a több szálú programozástól, de most nagyon kell. Adott egy FONTOS szál és egy HÁTTÉR szál. A FONTOS szálon futnak a program elsődleges feladatai, a HÁTTÉR szálon pedig szeretném kihasználni az elsődleges program holt idejét egy időigényes feldolgozásra.
Tehát ha a FONTOS szálnak feladata van ép, akkor a HÁTTÉR szál várakozzon, majd folytassa ha az elsődéegesnek ép nincs semmi dolga.
Egy program vázlat nagy segítség lenne. Gondolom egy TThread osztályt kellene létrehoznom és abban normál prioritással végeztetni a HÁTTÉR feladatokat. Persze a két szálnak kommunikálnia kell egymással és esetenként adatokat ill. üzeneteket váltani. Na, ebben abszolut nem vagyok otthon.
Minden tanácsot megköszönök!
Mutasd a teljes hozzászólást!
Nálam a HÁTTÉR szál nagy volumenű feladatot lát el.

Akkor miért háttérszál?  Tedd ki a funkcióit egy külön ~programba, ami idle prioritással folyamatosan aktív.
Amikor a könyvtárba új felvétel kerül, akkor ellenőrzi, hogy elég-e?  Ha igen akkor feldolgozza.
Mutasd a teljes hozzászólást!

  • Tehát ha a FONTOS szálnak feladata van ép, akkor a HÁTTÉR szál várakozzon, majd folytassa ha az elsődéegesnek ép nincs semmi dolga.

    Ha megnézed a thread suspend és resume metódusait, "deprecated" jelölésük van: ma már nem "illik" szálat felfüggeszteni és továbbküldeni ezekkel a triviális metódusokkal. "Igazi" kommunikációval viszont elég kódigényes megoldani, mert viszonylag gyakran ellenőrizni kéne, hogy jött-e felfüggesztésre felszólító üzenet a fő szálból.
    Ráadásul tulajdonképpen azt szeretnéd, hogy továbbra is egyszerre csak egy dolgot csináljon a program. Létezik egy olyan esemény, hogy TApplication.OnIdle Event , alapból egyszer kerül meghívásra, amikor a program úgy érzi, semmi dolga, de a dokumentáció szerint a "Done" paramétert false-re állítva majd újra meghívásra kerül. Szóval megpróbálhatsz egy olyat, hogy az idle eseménykezelődben valamit csinálsz mondjuk 0.1 másodpercig, és ha maradt még teendő, false-ra állítod a Done-t, hogy majd később folytathasd.
    Pl. ha eredetileg valami nagy ciklusod lenne

    for i:=0 to 999999999 do
    akkor ehelyett lesz egy i nevű tagváltozód, és lokálisan időkorlátozott ciklust futtatsz, kb.

    stop:=IncMilliseconds(Time(),100); while(i<=999999999 and Time()<stop) do begin ... i:=i+1; end; Done:=i>999999999;
    Mutasd a teljes hozzászólást!
  • Biztos, hogy meg akarod állítani a HÁTTÉR szálat, ha a FONTOSnak dolga van? Már régóta a többmagos processzorok világát éljük, ahol simán mehet a két dolog ténylegesen párhuzamosan, két különböző magon. (Az más kérdés, hogy egyéb erőforrások elérésében akadályozhatják egymást, pl. ha a HÁTTÉR sokat ír a diszkre, lehet hogy lassítja vele a FONTOS írásait, de ezt a pontos probléma ismeretében lehet mérlegelni.)

    Szerintem amit te akarsz, az egyszerűen a két szál prioritásának megfelelő beállítása (ha nincs idő mindkettőt futtatni, a FONTOS fusson inkább), illetve a szálak közti kommunikáció helyes implementációja. Esetleg ha a HÁTTÉR egymástól független feladatok végrehajtására való, akkor lehet nem is egy szál kell neked, hanem egy thread pool.

    A Delphihez nem értek, úgyhogy konkrét kóddal nem tudok szolgálni, hogyan tudsz üzeneteket küldeni és fogadni szálak között.
    Mutasd a teljes hozzászólást!
  • Nos, az az OnIdle esemény tényleg hasznos lehet egy viszonylag szolíd másodlagos programocska futtatásánál. Nálam a HÁTTÉR szál nagy volumenű feladatot lát el.
    Hogy konkrét legyek a fő program szál egy csillagtérképet jelenít meg, ami egérrel mozgatható. Benne objektumok kereshetők adattáblából. Ha utasítom, egy tácső elektronikának ad utasítást USB-n keresztül. Másik USB-vel egy fotókamerát vezérlek: expozíció start ill. stop. A kész képeket egy könyvtárba letölti.

    A HÁTTÉR szál végzi a felvételek feldolgozását. Ha van elég felvétel a könyvtárban, akkor feldolgozza és a kész képet egy másik könyvtárba menti. Ez roppant gép és időigényes munka.
    Viszont a fő program sokszor nem csainál semmit. Pl. az expozíciók indítása, majd leállítása közötti időben. Igaz egy Timer figyeli az időt közben. De ezt beállíthatom úgy, hogy csak az exp. végén induljon el az OnTimer esemény, amivel leállítja az exponálást.

    Úgy vélem itt a Thread ág lesz a megoldás.
    Mutasd a teljes hozzászólást!
  • TTask
    A háttér szál prioritása legyen tpIdle.
    Használhatod a TMessageManager-t az üzenetküldésre.
    Mutasd a teljes hozzászólást!
  • chiefa: ez a MessageManager nagyon hasznos ötlet. Még nem használtam, de látom az előnyeit.
    Mutasd a teljes hozzászólást!
  • Ugye azt is jó lenne tudni - a főprogramból lekérdezve -, hogy a HÁTTÉR szál hol tart a munkájával.
    Hiszen egy folyamatban lévő feldolgozást nem akarok megszakítani. Ha mégis, akkor kérdezzen rá.
    Mutasd a teljes hozzászólást!
  • Ez esetben nem érdemes a háttérszál felfüggesztésével-továbbindításával bajlódni. A főszál egyszerűen küldözgetheti akár sima PostThreadMessage-vel a tennivalókat, amiket a thread GetMessage-vel egyenként kiolvas és rögtön feldolgoz. TThread.Queue-val meg nagyon kényelmesen mesélheti, hogy hol tart. Elég ritkásak valahogy a komplett példák, de ez annak tűnik: Delphi threading by example
    Lehet WinAPI nélkül is szálazni amúgy, itt egy régebbi bevezető hozzá: Multithreading - The Delphi Way. 
    Ha valamiért katyvasznak tűnik ez a fajta szálkezelősdi, a jelek szerint mások is így érezték: több helyen javasolják a OmniThreadLibrary  használatát, ami jobban hasonlít a más nyelvekben megszokottakra.
    Mutasd a teljes hozzászólást!
  • Nálam a HÁTTÉR szál nagy volumenű feladatot lát el.

    Akkor miért háttérszál?  Tedd ki a funkcióit egy külön ~programba, ami idle prioritással folyamatosan aktív.
    Amikor a könyvtárba új felvétel kerül, akkor ellenőrzi, hogy elég-e?  Ha igen akkor feldolgozza.
    Mutasd a teljes hozzászólást!
  • chiefa: ez is jó ötlet. Csak abban segíts kérlek, hogy hogyan futtassam idle priorítással.
    Az adatcserét majd megoldom egy ini fájlon keresztül. Nem akarok belebonyolódni a win. messages rendszerébe.
    Mutasd a teljes hozzászólást!
  • Ma már a sz.gépek többsége több magos. Nem lehetne a HÁTTÉR feldolgozást egy másik magra bízni? Ebben a témában viszont teljesen járatlan vagyok.
    Mutasd a teljes hozzászólást!
  • Az, hogy melyik kód melyik magon fut, az oprendszer dolga, neked nem kell ezen aggódni. Beállítod az igényeidet (szálak prioritása), aztán ha van elég mag minden aktív szálnak, akkor kapnak egyet-egyet, ha nincs, akkor a prioritások alapján eldönti az oprendszer, hogy ki futhat és kinek kell várnia.

    (Ha nagyon akarod, lekorlátozhatod, hogy melyik szál melyik magon futhat, de ezzel inkább csak hátráltatod az ütemezőt, nem segíted.)
    Mutasd a teljes hozzászólást!
  • Igen, köszönöm. Közben én is megtaláltam ezt a trükköt. Vszínűleg tényleg külön programban írom meg a képfeldolgozást ami futtatás során megkapja paraméterként a prioritást.
    Mutasd a teljes hozzászólást!
  • Szerintem szálas megoldás jobb lehet.
    Nem kell inter process kommunikáció, vagy fájlrendszeren keresztül adatokat küldözgetni.

    Könnyebb egy process-en belül kezelni a dolgokat. Szerintem jobban jársz, ha időt fordítasz rá és átnézed a többszálú programozás alapjait, atomic, semaphore, mutex..
    (Az alapok felett nyilván van Delphi nyújtotta szinkronizációs objektumok, de winapi-s sem olyan vészes)
    Mutasd a teljes hozzászólást!
  • Mint mindig, zavarban vagyok, hogy melyik választ fogadjam el megoldásként. Ennek oka az, hogy nem csak egyetlen üdvözítő megoldás van. Több ötletet is kaptam Tőletek, amit szeretnék itt megköszönni. A téma még megérne egy misét, de valahol le kell zárni.
    chiefa válasza azért a legjobb nekem, mert a HÁTTÉR program szálat külön programként is szeretném használni.
    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