Hirdetés
- Mr Dini: Mindent a StreamSharkról!
- Luck Dragon: Asszociációs játék. :)
- gban: Ingyen kellene, de tegnapra
- sziku69: Fűzzük össze a szavakat :)
- NvidiaRTX: Xiaomi Electric Scooter 6 Max: Az első rollerem
- D1Rect: Nagy "hülyétkapokazapróktól" topik
- Candy: AOOSTAR WTR PRO – NAS, alkoss, gyarapíts
- Gurulunk, WAZE?!
- Luck Dragon: Alza kuponok – aktuális kedvezmények, tippek és tapasztalatok (külön igényre)
- balojazz: Szódakészítés üzembiztosan és olcsón! Figyelem, csak hardcore szódázóknak!
-
LOGOUT

Új hozzászólás Aktív témák
-
P.H.
senior tag
Van egy fejtörőm Windows-os többszálú programozással kapcsolatban. Röviden leírom az előzményeket, amit tudni kell hozzá, illetve milyen Windows API-hívásokat használ:
Adott egy egyszálú program, ami számításokat végez több 10000 lefutású ciklusban, minden lefutáshoz 1-8 db 16 MB méretű memória kell neki munkaterületnek (ilyen egységekben, tehát mindig x-szer 16 MB, sosem mondjuk 1x32 vagy 1x48); sosem több, mint 8x16 MB, és ez ki van nullázva, ezek a kezdőértékek. Ezeket egy-egy ciklus végén felszabadítja a program, majd a következő ciklustörzshöz megint lefoglal valahányszor 16 MB memóriát, használja, felszabadítja, stb...
Ezt a GlobalAlloc(GMEM_ZERO,méret) API-hívás meg is oldja, nullázott memóriaterületet ad a programnak, viszont a program contextusában nulláz, ezért lassítja a programot.Az első továbblépési ötlet az volt, hogy lefoglalok előre 8x 16 MB puffert, írok egy gyors nullázót (SSE non-temporal store-ral), illetve ehhez egy pár kezelőrutint:
- minden pufferhez tartozik egy bit a LOCKBITS változóban, a megfelelő x. bit 1 értéke jelzi, ha foglalt az x. puffer, 0 ha szabad
- GETBUFFER: kinulláz egy szabad puffert és ezt adja eredményül, illetve bejegyzi a LOCKBITS bitjébe, hogy foglalt, aztán visszaadja eredményül
- FREEBUFFER: megjelöli a puffert szabadnak a LOCKBITS bitjében
- RESTARTBUFFERS: alapállapotot állít vissza, azaz az összes puffert megjelöli szabadnak (pl. hiba volt a számításban, így nem futnak le a megfelelő FREEBUFFER-ek); azaz praktikusan a LOCKBITS minden bitjét törli
Ez még mindig egyszálú program, viszont nincs GlobalAlloc és GlobalFree hívás futás közben, tehát gyorsabb.A továbblépéshez az SSD-k TRIM megoldását használtam fel: a puffert nem a GETBUFFER hívásnál nullázom ki, amikor már szükség van rá, hanem a felszabadításkor a FREEBUFFER hívásban. Mivel akkor már nem kell az a memóriaterület, ezért egy külön szálon (CREATETHREAD) hívom meg a nullázó eljárást, így a számítási szál nyugodtan futhat tovább, nem zavarják egymást. A kezelés is kicsit módosult:
- bevezettem egy PENDINGS változót a LOCKBITS mellé, amelynek 1 bitje jelzi, ha az adott puffer már nem használt, de még nem szabad, mert nullázása folyamatban van. Ez mindjárt kiderül, hogy miért kell, mivel a fenti kezelőrutinok a következőképpen módosultak:
- FREEBUFFER: megjelöli a puffert a PENDINGS bit-jében 1-re, és kreál egy szálat, ami kinullázza majd valamikor azt. A szál ha elindul majd valamikor, akkor kinullázza a memóriát, és »miután« kész van, akkor egyszerre törli a puffer bitjét a LOCKBITS és a PENDINGS változóban is.
- GETBUFFER: átnézem a LOCKBITS-ben, hogy van-e szabad puffer. Ha nincs, akkor a PENDINGS-ben bejelölt puffer-ek szálait összegyűjtöm és várok addig, amíg egy el nem készül a nullázással (WAITFORMULTIPLEOBJECTS any), aztán az ő címe lesz az eredmény.
- RESTARTBUFFER: összegyűjti a PENDINGS-ben bejelölt puffer-ek szálait, megvárja, amíg az összes elkészül a nullázással (WAITFORMULTIPLEOBJECTS all), majd azokra, amik foglaltak maradtak (A LOCKBITS bit be van állítva), meghívja a nullázót az összes pufferre, a program contextusában (ezt már nem szépítsük, hiba volt, úgyis mindegy).
Tehát a state-átmenetek egy pufferre:
1. szabad (LOCKBITS = 0) felhasználható
-> 2. foglalt (LOCKBITS = 1, PENDINGS = 0)
-> 3. még nem szabad (LOCKBITS = 1, PENDINGS = 1) erre érdemes várni
-> 1. szabad (LOCKBITS = 0)Ez a megoldás így konzisztens, működőképes (kb. 60-70%-ra terhel egy 8 magos gépet). Viszont mivel minden törléshez új szálat hozok létre és a lefutás után megszüntetem, a kernelidő nagyobb, mint szeretném (kb. 5%). Ezért jobb lenne egy olyan megoldás, ami előre létrehozná a 8 szálat is mindegyik puffer mellé, amik "végtelen" ciklusok lennének, csak egy-egy nullázás után egy event-re várnának (WAITFORSINGLEOBJECT), ezt a FREEBUFFER állítja be nekik, akkor lefuthat a következő nullázás; ha készen vannak, akkor beállítanak egy event-et, végeztek. Gyakorlatilag watchdog-szerűségek lennének, amik várnak, viszont rájuk is kell várni néha.
A nehézséget azok az esetek jelentik, amikhez a fenti működő megoldásban WAITFORMULTIPLEOBJECTS kell: mivel egy-egy thread-nek van default egy event-je (ezt a Windows hozza létre), ami 0, ha még fut és 1, ha lefutott. A program 3 esetet különböztet meg ezáltal:
-> szabad puffer
-> foglalt puffer és nincs törlőszála (felhasználás alatt)
-> foglalt puffer és van törlőszála (mindjárt szabad)A probléma az, hogy az event-ek ugyan 1 bites változóknak tűnnek, de nem lehet lekérdezni közvetlenül az értéküket, csak a következő játékszerek vannak:
- SETEVENT: beállítja 1-re az event-et
- RESETEVENT törli 0-ra az event-et
- WAITFORSINGLEOBJECT: megállítja a szálat és megvárja, amíg 1 lesz az event, amit kapott, akkor engedi tovább a szál futását
- WAITFORMULTIPLEOBJECTS any: megállítja a szálat és megvárja, amíg a paraméterül kapott eventek bármelyike 1 lesz, akkor engedi tovább a szál futását
- WAITFORMULTIPLEOBJECTS all: megállítja a szálat és megvárja, amíg a paraméterül kapott eventek mindegyike 1 lesz, akkor engedi tovább a szál futását
Továbbá az event-et lehet kreálni úgy, hogy csak addig maradjon 1, amíg ki nem olvassa WAITFORMULTIPLEOBJECTS vagy WAITFORSINGLEOBJECT, úgy is lehet kreálni, hogy mindig kézzel kelljen törölni 0-ra.Rövidre lehetne zárni az egészet, ha a főszál, aminek várnia kell (a GETBUFFER-ben vagy a RESTARTBUFFER-ben) beolvassa a PENDINGS biteket egy regiszterbe majd elindít egy ciklust, ami folyamatosan hasonlítja össze az aktuális PENDINGS biteket a regisztettel, hogy van-e változás, de ez ugye egy magot teljesen leterhel; ha beiktatok a ciklusba egy SWITCHTOTHREAD hívást is, akkor nem terheli le a magot, de ki tudja, hova kerül a vezérlés (csak elkapcsol innen, nincs paramétere) és mikor kerül vissza. Ennél elegánsabb megoldás jobb lenne.
Ha van valakinek ötlete, hogy hogyan lehetne hatékony konzisztens rendszert felépíteni a fenn vázolt feladatra event-ekkel és az 5(+1) eszközzel, vagy valami mással, ne tartsa magában

Új hozzászólás Aktív témák
● olvasd el a téma összefoglalót!
- Eladó Xiaomi Redmi Buds 8 Lite!
- 337 Eladó keveset használt Xerox Versalink B7030 a képek szerinti állapotban új tonerrel
- Eladó Xiaomi Smart Band 10 okoskarkötő!
- Asus Tuf Gaming A16 ÚJ // Ryzen 7 // RTX 5070 // Számla // Garancia //
- Legion Slim 5 16ARP9 15.6" QHD+ IPS Ryzen 7 7435HS RTX 4060 16GB 512GB NVMe gar
- LG 27MR400 - 27" IPS LED - 1920x1080 FHD - 100hz 5ms - AMD FreeSync - Villódzásmentes
- GYÖNYÖRŰ iPhone 12 Mini 64GB Black -1 ÉV GARANCIA - Kártyafüggetlen, MS4167, 94% Akksi
- Dell Inspiron 15 5567
- GAMER PC! i7-14700 / RTX 5080 / 32GB DDR5 / 1TB NVMe / 1000w Gold / BeszámítOK !
- Apple iPhone 13 mini / 128GB / Kártyafüggetlen / 12Hó Garancia / Akku: 87%
Állásajánlatok
Cég: Laptopműhely Bt.
Város: Budapest


