- Szünetmentes tápegységek (UPS)
- Notebook hibák
- AMD Ryzen 9 / 7 / 5 7***(X) "Zen 4" (AM5)
- Kötelező BIOS frissítéssel orvosolná a Core CPU-k stabilitási gondját az Intel
- Házimozi belépő szinten
- Hobby elektronika
- Épített vízhűtés (nem kompakt) topic
- SSD kibeszélő
- AMD vs. INTEL vs. NVIDIA
- VR topik (Oculus Rift, stb.)
Hirdetés
-
Toyota Corolla Touring Sport 2.0 teszt és az autóipar
lo Némi autóipari kitekintés után egy középkategóriás autót mutatok be, ami az észszerűség műhelyében készül.
-
A vártnál kevesebb iPad Pro fogyhat
ma A tandem OLED panel előremutató, ám drága, az olcsóbb iPadek lehetnek népszerűek.
-
Android és iOS rendszerekre érkezik a Sonic Rumble
gp A május végére tervezett zárt bétára már lehet jelentkezni a hivatalos oldalon.
-
PROHARDVER!
Ú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
[ Szerkesztve ]
Arguing on the Internet is like running in the Special Olympics. Even if you win, you are still ... ˙˙˙ Real Eyes Realize Real Lies ˙˙˙
Új hozzászólás Aktív témák
● olvasd el a téma összefoglalót!
- Foxpost
- A fociról könnyedén, egy baráti társaságban
- Politika
- bb0t: Gyilkos szénhidrátok, avagy hogyan fogytam önsanyargatás nélkül 16 kg-ot
- Szünetmentes tápegységek (UPS)
- Notebook hibák
- Székesfehérvár és környéke adok-veszek-beszélgetek
- AMD Ryzen 9 / 7 / 5 7***(X) "Zen 4" (AM5)
- D1Rect: Nagy "hülyétkapokazapróktól" topik
- Samsung Galaxy S23 Ultra - non plus ultra
- További aktív témák...
- Samsung Galaxy S24+ 5G 256GB, Kártyafüggetlen, 1 Év Garanciával
- Samsung Galaxy A12 64GB, Kártyafüggetlen, 1 Év Garanciával
- Dell Latitude E7470 - i5 6200U / 8-16GB RAM - számla, 6 hó garancia
- Samsung Galax Tab A7 Lite 32GB, Újszerű, 1 Év Garanciával
- Samsung Galaxy A32 128GB, Kártyafüggetlen, 1 Év Garanciával
Állásajánlatok
Cég: Ozeki Kft.
Város: Debrecen
Cég: Promenade Publishing House Kft.
Város: Budapest