Zobrazit předchozí téma :: Zobrazit následující téma |
Autor |
Zpráva |
Játro.m
Založen: 01. 02. 2010 Příspěvky: 230
|
Zaslal: 28. červen 2012, 09:48:01 Předmět: Sdílená paměť |
|
|
Nazdar,
problém je asi takový, mám jednu třídu, dejme tomu že v mém případě má následující strukturu:
kód: |
class Character
{
public:
...
Sound * deathSound, *hitSound, footSteps;
Grenades grenades;
xmAnimation character;
Shield shield;
Magnet magnet;
...
private:
vec3 pos, rot;
}; |
Většina z těchto instancí má dynamicky alokovanou paměť, kterou potřebuju občas při běhu uvolnit a znova naplnit.
Z této třídy udělám jednodušše pole:
kód: |
character = new Character[4]; |
A konečně se dostávám k problému, tato třída - pole z ní je v hlavní smyčce sdíleno mezi dvěma vlákny - sítě a vykreslování.
Můj postup je takovej, že pole vytvořím v vlákně [sítě], v vlákně [načítání] načtu resource z disku, toto vlákno pozastavím a začnu [vykreslovat].
Do pole zapisuje ze začátku vlákno [načítání], který se pozastaví a převezmou kontrolu [sítě]. V renderingu se z této třídy jenom čte, a data se teda nepoškodí.
Hlavně, obsah zapisovanejch dat z [sítě] jsou obyčejný booleany a pár vektorů, do toho co se kreslí to nešahá, jen se podle příznaků přenastavují animace a podobně.
Toto je všechno v pohodě, jenom jakmile potřebuju tuto paměť uvolnit, tak se to chová jako posunutej pointer nebo špatnej - paměť se neuvolní i když zastavím všechny vlákna, i při vypnutí programu v destruktorech dostanu chyby, že se to nepodařilo uvolnit.
Upřímně, moc toho o multi-threadingu v tomhle směru netuším, jestli musím alokovat a dealokovat ve stejnejch vláknech, nebo je celá tahle navržená struktura na dvě věci?
Takže shrnutí, jak se má zacházet správně s pamětí, která je sdílená mezi vlákny?
Díky za odpovědi. _________________ Jeden z vývojářů hry Grenade Madness. |
|
Návrat nahoru |
|
 |
Weny Sky

Založen: 28. 07. 2007 Příspěvky: 241
|
Zaslal: 28. červen 2012, 11:33:05 Předmět: |
|
|
- V ramci procesu je jedno kde, jak, proc, ... alokujes a uvolnujes pamet.
- S pameti mas zachazet tak, ze spravne synchronizujes pristup do kritickych sekci.
Problem bych videl v tom, ze si nekde poskodis pamet uplne necim jinym. Napriklad zapis mimo rozsah alokovaneho pole.
Jeste me potom napada varianta, ze linkujes proti single-thread standardnim knihovnam, takze pak je mozne, ze napriklad malloc/new poskodi haldu. Nebo nejake jina funkce. |
|
Návrat nahoru |
|
 |
mar
Založen: 16. 06. 2012 Příspěvky: 610
|
Zaslal: 28. červen 2012, 12:35:09 Předmět: |
|
|
No myslím, že by to mělo být jedno. Pokud děláš ve VS, tak tam už myslím statický runtime stejně ani není podporován.
Jde o to, jak se ti to chová. Jestli to padá, tak tam asi bude zápis někam mimo, jak už bylo napsáno.
Jestli se to jenom neuvolňuje, tak se možná ještě jednou ujistit, že se pole dealokují pomocí delete[] místo delete. Může se stát, že to člověk někde přehlédne.
Poslední, co mě napadá, je, jestli se tam neuvolňuje už uvolněný blok. To by taky mohl být problém.
V debug módu by se ty bloky měly vyplňovat např. po uvolnění atd., viz např. tady: http://www.nobugs.org/developer/win32/debug_crt_heap.html
Takže pokud tam někde bude v pointerech něco jako 0xfeeefeee, pak je to ono. |
|
Návrat nahoru |
|
 |
Játro.m
Založen: 01. 02. 2010 Příspěvky: 230
|
Zaslal: 28. červen 2012, 12:47:51 Předmět: |
|
|
Pro upřesnění, kompiluju pod minGW, pole mažu určitě delete[], teď jsem to ještě kontroloval a uvolnění nepadá, jenom mi zůstane viset alokovaná paměť. VRAM kterou mažu v destruktorech se taky neuvolní, protože po vypnutí vidím visící shadery v paměti. Dělá to jenom tento kód, ve zbytku enginu je to různě použitý a smaže se to samo.
Na uvolněný bloky se podívám, ono to chování je takový, že se prvně smaže pole a potom se až volají destruktory, místo aby se prvně zavolaly destruktory v modelech a až potom se zničilo pole. _________________ Jeden z vývojářů hry Grenade Madness. |
|
Návrat nahoru |
|
 |
pcmaster

Založen: 28. 07. 2007 Příspěvky: 1827
|
Zaslal: 28. červen 2012, 13:27:04 Předmět: |
|
|
No tak to chovanie je zle
Zvaz pouzivanie std::unique_ptr a std::shared_ptr vsade, kde sa len da -- je to ISO C++, funguje uz aj na predpotopnom VC++ 2010 (na GCC este lepsie) a, ako povedal typek z MS v zaujimavej, tu linkovanej video prezentacii o C++11, "uz nikdy nebudes musiet zavolat delete"
Samozrejme, problemov s kritickymi sekciami ta to nezbavi, to si musis doriesit tak, ci tak, presne ako pise Weny. _________________ Off-topic flame-war addict since the very beginning. Registered since Oct. 2003!
Interproductum fimi omne est. |
|
Návrat nahoru |
|
 |
mar
Založen: 16. 06. 2012 Příspěvky: 610
|
|
Návrat nahoru |
|
 |
Tringi

Založen: 28. 07. 2007 Příspěvky: 290
|
Zaslal: 28. červen 2012, 13:48:39 Předmět: |
|
|
Udělej si kopii a začni program redukovat do úplně nejmenší verze, v níž se problém bude stále projevovat.
Pokud odebráním nějaké části problém zmizí, dá ti to dost dobré vodítko k nalezení chyby, i když ta nemusí být zrovna právě v té odebrané části. Pokračuj pak odebíráním jiných částí.
Pokud se dostaneš pod sto řádků a stále nebudeš vědět čím to, pak postni takto redukovaný kód sem a to by v tom byl čert, aby na to někdo nepřišel. _________________ WWW | GitHub | TW |
|
Návrat nahoru |
|
 |
Játro.m
Založen: 01. 02. 2010 Příspěvky: 230
|
Zaslal: 9. červenec 2012, 17:30:21 Předmět: |
|
|
tak po odpoledni debugování jsem na to přišel,
1) vlákno se musí při uvoňování paměti uplně suspendnout funkcí SuspendThread, nestačí aby v smyčce byl return.
2) problém neuvolňování a chování se jako poškozenej pointer způsobovaly interní destruktory třídy, který se mě z naprosto neznámýho důvodu občas samy zavolaly i v renderu ?!? WTF, ale snad ani nechci vědět proč.
Takže řešení bylo, zaházet destruktory rodičovskejch tříd, nechal jsem jenom destruktory tříd ze kterejch se dělaj pole a ostatní destrukty jsem nacpal do vlastní třídy kterou volám při reloadu mapy / zavření okna.
Dík za nápady ;D _________________ Jeden z vývojářů hry Grenade Madness. |
|
Návrat nahoru |
|
 |
Tringi

Založen: 28. 07. 2007 Příspěvky: 290
|
Zaslal: 9. červenec 2012, 23:47:25 Předmět: |
|
|
Chlape ty děláš něco hodně hodně špatně.
Tvé 1 i 2 je totální blbost, někde si přepisuješ paměť nebo něco, a budeš-li postupovat dál, dřív nebo později se zasekneš tak, že budeš moct celý projekt zahodit. _________________ WWW | GitHub | TW |
|
Návrat nahoru |
|
 |
nou

Založen: 28. 07. 2007 Příspěvky: 1050
|
Zaslal: 10. červenec 2012, 07:01:48 Předmět: |
|
|
to ze sa ti volaju pravdepodobne pretoze sa ti niekde kopiruju. skus si spravit kopirovaci konstruktor a sprav ho protected. potom ti vyhlasi chybu pri preklade ak sa niekde takyto objekt budes snazit skopirovat. _________________ Najjednoduchšie chyby sa najtažšie hľadajú. |
|
Návrat nahoru |
|
 |
Játro.m
Založen: 01. 02. 2010 Příspěvky: 230
|
Zaslal: 10. červenec 2012, 07:49:50 Předmět: |
|
|
Dík! Měli ste pravdu, ikdyž bych se zapřísáhl, že jsem to kopírování tam neměl, tak fakt na jednom místě bylo, problémy zmizely uplně.
Btw tringi, k tomu pozastavení vlákna. Řekni víc, co je na tom špatně, jsem v MT uplnej zelenáč a tuhle metodu jsem zvolil z důvodu, že když jsem začal mazat data který jsou sdílený mezi dvě/tři vlákna, tak mi to občas naprosto náhodně hodilo nedoledatelnej segfault. Pozastavení ostatních vláken kromě renderu a reloadu tohle vyřešilo. _________________ Jeden z vývojářů hry Grenade Madness. |
|
Návrat nahoru |
|
 |
Marek

Založen: 28. 07. 2007 Příspěvky: 1782 Bydliště: Velká Morava
|
Zaslal: 10. červenec 2012, 14:19:35 Předmět: |
|
|
Přístup ke sdílené struktuře dej do kritické sekce.
SuspendThread je fakt totální blbost. _________________ AMD Open Source Graphics Driver Developer |
|
Návrat nahoru |
|
 |
Tringi

Založen: 28. 07. 2007 Příspěvky: 290
|
Zaslal: 10. červenec 2012, 15:25:59 Předmět: |
|
|
Játro: Pozastavení vlákna nevyřešilo tvůj problém, pouze zmenšilo pravděpodobnost že se projeví. SuspendThread bez okolků zastaví tvé vlákno klidně uprostřed destruktoru, uprostřed uvolňování paměti (a způsobit poškození heapu), uvnitř kritické sekce nějakého api (a způsobit deadlock jiných vláken) nebo třeba APC což je úplně jiná bestie.
Moje rada by byla: Pokud nemáš bottleneck na procesoru, přestaň používat vlákna, úplně. Pokud nevíš jak to udělat bez nich, použij nějakou vyšší knihovnu, nebo si nejprve alespoň nastuduj k čemu jsou mutexy/kritické sekce.
Když čtu tvoje "mazat data sdílený mezi vlákny" tak dostávám kopřivku. Sice jsem kdysi začínal stejnými pokusy, ale zabil jsem neskutečně času a nervů koukáním do kódu a bojem s neodladitelnými heisen-chybami. A přitom stačilo věnovat trochu času a nejprve si o tom něco přečíst. _________________ WWW | GitHub | TW |
|
Návrat nahoru |
|
 |
Játro.m
Založen: 01. 02. 2010 Příspěvky: 230
|
Zaslal: 10. červenec 2012, 16:27:32 Předmět: |
|
|
Tringi, aha, ono jedna věc je studovat dokumentaci a druhá to zkusit prakticky, jakmile jsem viděl, že to funguje tak jsem to dál neřešil, no nevadí, zkusím popsat problém podrobně.
Ono řekněme, že v současné době dodělávám multiplayer pro realtime TPS, proto jsem zvolil použití vláken kvůli blokujícím soketům a možnosti si stavy ze sítě zpracovat v dalším vlákně.
Z toho důvodu, že ty dvě vlákna běží odděleně, není v síťovým vlákně kritická sekce, je jenom mezi renderem a načítáním, protože jsem se kvůli sítím dostával do deadlocku.. Zase, už v tomhle ohledu jedu od boku, protože nikde sepsán nějakej přesnej postup, jak by to mělo přesně vypadat. Proto jsem udělal jak říkáte blbost, že před každým reloadem mapy pozastavím vlákno který zpracovává data ze sítě a zbytek běží dál - načítání a render.
A pokud vím, tak kritickou sekci může v jednom okamžiku vlastnit jenom jedno vlákno, takže když zamknu sítě a render do jedné sekce a nastane náhodou lag, ztratí se paket nebo cokoliv, tak ta smyčka co renderuje se pozastaví přece taky ne?
Pokud v tom mám bordel, tak doufám, že budete tolerantní :D.
Budu rád za každej názor jak by jste to řešili vy. _________________ Jeden z vývojářů hry Grenade Madness. |
|
Návrat nahoru |
|
 |
rezna
Založen: 27. 07. 2007 Příspěvky: 2156
|
Zaslal: 10. červenec 2012, 17:00:42 Předmět: |
|
|
pouzij neblokujici sockety pomoci windowsich zprav
co se zamykani tyce - zamykaji se pouze kriticka mista, kam se zapisuje a je to sdileno
navic nikdo nerika ze musis zamknout pri cteni ze site
nactes ze site do pomocnych promennych (nehlede na to jakej je lag) - jakmile mas nacteno, zamknes data, prepises, odemknes
zamyka na nezbytne nutnou a nezbytne minimum - jinak samozrejme skoncis v dead-locku a nebo naopak nezamknes a jsi v race conditione
EDIT:
takze hlavni je toto - ty tu ted podrobne popis, co ktere vlakno dela, a ktera jsou ta sdilena data, pripadne proc uvolnujes data z jineho vlakna, nez ktere ho vlastni (to je typicky kamen urazu) |
|
Návrat nahoru |
|
 |
|