Skocz do zawartości
Isharoth

C++ | SDL2 - Wielowątkowość w pętli

Rekomendowane odpowiedzi

Cześć, zacząłem zabawę z wielowątkowością w C++ i jednej rzeczy nie rozumiem. Kiedy wrzucę joina do pierwszej pętli, wtedy program działa prawidłowo, ale jednak wolniej niż na pojedynczym wątku (co jest akurat zrozumiałe). Chciałbym jednak, żeby wszystkie wątki wykonały swoje zadanie, a główny wątek grzecznie poczekał aż wszystkie będą gotowe. Niestety gdy zrobiłem drugą pętlę, w której dołączam wszystkie wątki, to program się zamyka. W jaki sposób mogę to ugryźć?

 

std::thread t[8];
for (int j = 0; j < 8; ++j)
{
  t[j] = std::thread(&Map::threadDraw, this, j, tiles_size, Tiles);
}

for (int j = 0; j < 8; ++j)
{
  t[j].join();
}

 

Mam pętlę, która wykonuje się nawet kilkadziesiąt tysięcy razy (teraz pętla znajduje się w funkcji threadDraw). Podzieliłem to zadanie tak, aby każdy wątek miał do wykonania taką samą część pracy. Niestety nie wiem jak to zrobić w dobry sposób i z czego skorzystać, bo na pewno czegoś tu brakuje.

 

Doczytałem, że problem może powodować SDL (bo piszę grę). Podobno funkcje z SDL operujące na renderze, muszą być wykonywane na wątku, w którym ten renderer został stworzony. Tyle, że osoba która to pisała zaznaczyła, że dotyczy to sytuacji, w której wykorzystujemy OpenGL, podczas gdy ja mam obecnie DirectX. Jeśli rzeczywiście problem leży gdzieś tutaj to chyba sobie daruję wielowątkowość, bo musiałbym przepisać połowę kodu, a mam tydzień czasu na skończenie tego. szczerbaty.gif

Z drugiej strony, wątpię że to akurat ten sam problem, bo przecież tak czy inaczej wykonuję to samo na różnych wątkach. Kwestia tego kiedy dołączę dany wątek, a niestety rozwiązanie jakie przedstawiłem wyżej kończy się crashem.

Edytowane przez Isharoth

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Najbezpieczniej jest rysowac w jednym tylko watku i w 99,99% przypadkow to jest wystarczajace do osiagniecia liczby FPS ktorej potrzebujesz. Nie widze powodu dla ktorego mialbys renderowac w roznych watkach jednoczesnie. Bo na pewno nie jest to wydajnosc.

 

Powinienes rysowac w jednym watku i zrobic konstrukcje w ktorej polecenia pobierane sa z kolejki do ktorej dostep jest synchronizowany.

 

Alternatywna metoda - utworzyc sobie mutex i w momencie kiedy wywolujesz metode ktorej wynikiem sa calle do renderea przejmowac wlasnosc na tym mutexie. Czyli de facto tez synchronizowac rysowanie. W ten sposob sprawisz ze renderowanie bedzie thread safe.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Jeśli chodzi o samo rysowanie to tak, niestety grę wcześniej pisałem bez myśli o wielowątkowości i teraz wychodzą takie problemy. Debuger wskazuje na RenderCopy, czyli jednak to jest to. Co ciekawe na DirectX gra crashuje, na OpenGL działa, ale nie rysuje poprawnie mapy.

Myślałem o wielowątkowości, bo każdy bloczek rysowany na mapie traktuję jako osobny obiekt. Więc w pętli w której rysuję mapę przy mapie 160x160 odwołuję się do 25600 obiektów, sprawdzam ich właściwości, animacje i renderuję na mapie w odpowiedniej pozycji. Na Ryzenie 2700X wychodzi około 90 fps, co nie jest zbyt dobrym wynikiem jak na grę 2D lol2.gif. Niestety trzeba by tu było część rzeczy przepisać. Zastanowię się jeszcze nad tym co napisałeś, bo sam póki co nie mam żadnych pomysłów.

Czytałem o tych mutexach, ale póki co nie ogarniam o co chodzi. Dzięki bardzo za propozycje! :)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Problem polega na tym, ze nie ogarniasz programowania wspolbieznego. Doczytaj sobie o tym i o podstawowych mechanizmach synchronizacji.

 

Temat jest ciekawy i warty zglebienia :)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Naiwne zrównoleglenie + synchronizacja może się skończyć gorzej niż wariant jednowątkowy...

 

Profilowałeś program, czy optymalizujesz "na pałę"?

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Profilowałeś program, czy optymalizujesz "na pałę"?

Na pałę nie. Wszystko dotyczy operacji która powtarza się najczęściej i zabiera sporo fps. Samo rysowanie mapy składającej się z 25600 bloczków i mam spadek z ~2500fps do 90 fps. Na pewno da się to zrobić w lepszy sposób, ale grę muszę mieć skończoną do następnego tygodnia (projekt na studia). Pewnie będę dalej nad tym pracować w ramach hobby. Problem w tym, że mam jedną prostą pętlę przy rysowaniu mapy, w której odwołuję się do każdego bloczku i rysuję jego teksturę w odpowiednim miejscu. No i tu moim gwoździem do trumny jest to, że SDLowe RenderCopy będzie zawsze wywoływane z poziomu klasy bloczku (a raczej mojego texture managera, do którego odwołuję się w tej klasie) i tu się cały program wysypuje przy wielowątkowości. Gdybym brał wcześniej pod uwagę, że będę próbował robić multithreading, to pewnie rozpisałbym to inaczej. Na początku myślałem, że będzie dało się rozłożyć tą prostą pętlę na wątki, jednak problem jest bardziej złożony, a ja pierwszy raz w ogóle ruszałem wielowątkowość przy programowaniu. bigsmile.gif

 

I tak już zoptymalizowałem co się dało, bo wcześniej było poniżej 60 fps przy tym samym rozmiarze mapy. Po prostu zrobię mniejsze mapki, a jak skończę robić tę grę, to i tak raczej przepiszę cały silnik od podstaw i to już nie na SDL, tylko czystym OpenGL, bo z shaderami też chciałbym się pobawić. :)

Edytowane przez Isharoth

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Przy tygodniowym deadline odpuść jakąkolwiek wielowątkowość ;)

 

Jeżeli coś by miało jakieś szanse zadziałać, to użycie wątków tak, by każdy niezależnie składał swoją 1/8 ostatecznego obrazu, i dopiero w głównym wątku to wszystko złożyć w całość. Jak i czy to wykonalne - mnie nie pytaj, nie tykałem SDL'a od lat :P

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach
samo rysowanie mapy składającej się z 25600 bloczków i mam spadek z ~2500fps do 90 fps

Zastanawia mnie po co Ci 2500 fps? 90 fps to dobry wynik, chociaz na pewno mozna go poprawic, jednak bedzie to kosztowalo troche czasu.

 

Bez wiekszej ilosci kodu trudno bedzie pomoc :)

 

Twoj problem polega na tym, ze program nie dostarcza wystarczajaco szybko danych do potoku karty graficznej. Profilowanie byloby wskazane. Nawet najprostsze i lopatologiczne na poczatek z manadzerem zadan i programem GPU-Z i interesuje Cie "gpu load".

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Zastanawia mnie po co Ci 2500 fps? 90 fps to dobry wynik, chociaz na pewno mozna go poprawic, jednak bedzie to kosztowalo troche czasu.

 

Tak, ale jak 90 fps mam na 2700X, to ile będzie na słabszych CPU? Właśnie o to się martwiłem, tym bardziej jakbym chciał zrobić jeszcze większe mapy. Przed optymalizacją na moim laptopie było jakoś ~40fps, bardzo słabiutko jak na grę 2D, a to tylko mapa z bloczkami, które mają swoje właściwości. A za optymalizację też będę oceniany. lol2.gif Cały spadek wydajności obraca się tylko wokół tej jednej, prostej pętli w której wywołuję metodę update dla 25 tys. obiektów, dlatego właśnie to chciałem rozdzielić na wątki. :)

GPU raczej nie ma za dużo do roboty.

 

W grze działa mi nawet OSD z Afterburnera, więc wszystko mam pod ręką. Użycie GPU na minimalnym taktowaniu skacze od 5 do 30%. Zwracam jednak szczególną uwagę na CPU, bo nawet gdy na próbę zakomentowałem całą metodę update, to zobaczyłem, że samo wywoływanie tylu obiektów zabiera aż tyle fps. A jeden wątek CPU jest prawie cały czas na 100%. wink.gif

 

Haha, problem leżał w mojej iteracji wektora. Po zmianie pętli na:

 

for (auto& i : Tiles)
{
  i->update();
}

całość działa 4 razy szybciej. szczerbaty.gif

Edytowane przez Isharoth

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Pokaz poprzednia wersje :)

Sprawdzasz to na konfiguracji debug? Bo jesli tak to jest kompletnie niemiarodajne.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Wcześniej było tak:

 

for (int i = 0; i < tiles_size; i++)
{
	Tiles[i]->update();
}

 

 

Ok, po zmianie sposobu iteracji miałem 390fps, teraz po zmianie konfiguracji na release mam ~1500. lol2.gif Problem z głowy, bez wielowątkowości (ale i tak do tego przysiądę). Dzięki za pomoc. :)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Jest ktoś w stanie wytłumaczyć skąd taka różnica w wydajności między tymi dwiema pętlami?

Na moje oko i to co znalazłem w sieci, to nie powinno być tak dużej różnicy.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Operator [] wykonuje dodatkowe operacje do sprawdzenia czy jesteśmy in range.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

operator[] nie wykonuje sprawdzenia zakresu.

iterowanie po zakresach powoduje uzycie kilku sprytnych optymalizacji - doczytaj w necie bo duzo by wymieniac.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Autor dokonał zmiany jeszcze w momencie, gdy prowadził "pomiar" w debug.

A tam - przynajmniej w implementacji ms - operator[] sprawdza zakres.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

To ciekawie by było porównać obie wersje w release.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach
Napisano (edytowane)

Chętnie sprawdzę jutro i dam znać. Bo dziś siedziałem nad tym tyle, że nawet nie mam już więcej ochoty wracać do Visual Studio. szczerbaty.gif

 

Na release nie widzę różnicy.

Edytowane przez Isharoth

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się

  • Ostatnio przeglądający   0 użytkowników

    Brak zarejestrowanych użytkowników przeglądających tę stronę.

  • Tematy

  • Odpowiedzi

    • No to jak ci ześrubowali, i to na stałe, to pierwszy etap leczenia bardzo szybki, byle się zagoiło po operacji. Prawie brak unieruchomienia, byle potem nabrać pełnej wytrzymałości kości. Porównywanie takiego złamania do stopy nie ma najmniejszego sensu. Tu masz jedną dużą kość, o niewielkiej ruchliwości. W stopie pełno drobnych, powiązanych ze sobą i wbrew pozorom sporej ruchliwości. To zupełnie inna mechanika, więc i gojenie będzie inne. Przy jeździe stopy nie przenoszą ciężaru ciała, chyba że bawi się w jakieś zjazdy, skoki itp. Pytanie czy tam gdzie było złamanie, czy tak ogólnie puchną nogi. W drugim przypadku, to pewnie kwestie krążeniowe.
    • „Polska gurom”. Ładnie wytrzymał.    O zmianach oficerów i mobilizacji nic nie wiadomo. Z jakiego powodu zostali usunięci, są tylko plotki że dostawali w łapę i dużo przepuszczali na zachód. Czy szła źle? No nie, bo od początku brali tylko w miarę przeszkolonych, ochotników i przeszkolonych. O mobilizacji (tej na mięsne wkładki) wiadomo dopiero od teraz, i to że rząd Ukrainy tej mobilizacji nie chciał podjąć wcześniej.    Każdy obrywa od artylerii i fabow, ale żadna jednostka nie oberwała na tyle by wyłączyć ją z frontu, czyli można wnioskować że straty są akceptowalne. Ukraińcy od dawna powtarzają, wolą przeszkolonych niż nie którzy mogą powodować to że cała kompania pójdzie do piachu. Azov na tyłach szkoli ludzi, część 47 też miała to robić.  O porzuceniu frontu słyszeliśmy na razie dwa razy, ostatnio świeża sprawa z 110 elementem brygady podczas rotacji oraz rotacji pod Soledarem, więc gdzie jeszcze uciekają niczym Rosjanie szturmują?    O załamaniu frontu mówili w momencie braku wsparcia z USA. Jak to się koreluje do mobilizacji? A no właśnie tak, że ludzi może i jest ale sprzętu brak. 
    • Cześć, trochę rzeczy mi się zalęgło przez jakiś czas i pora zrobić małą wyprz Dla labowiczów ceny do negocjacji. Dysk Western Digital 6TB NASware 3.0: https://www.olx.pl/d/oferta/western-digital-6tb-nasware-3-0-CID99-IDZROd1.html?bs=olx_pro_listing MiniPC Zotac ZBOX IQ01: https://www.olx.pl/d/oferta/minipc-zotac-zbox-iq01-intel-i7-4770t-CID99-IDZROPY.html?bs=olx_pro_listing MiniPC Zotac ZBOX nano ID67: https://www.olx.pl/d/oferta/minipc-zotac-zbox-nano-id67-CID99-IDZROsz.html?bs=olx_pro_listing HP J9803A 1810-24G: https://www.olx.pl/d/oferta/switch-hp-1810-24g-j9803a-CID99-IDZRNAA.html?bs=olx_pro_listing NAS Synology DS720+ razem z: HDD: 2x Seagate IronWolf 8TB NAS NVMe cache: 2x Samsung 970 EVO Plus 1TB https://www.olx.pl/d/oferta/synology-ds720-2x8tb-2x1tb-nvme-CID99-IDZRNpL.html?bs=olx_pro_listing Intel NUC  BXNUC10i7FNK2: https://www.olx.pl/d/oferta/intel-nuc-i7-10710u-6-rdzeni-32gb-ddr4-128gb-m2-nvme-ssd-nas-serwer-CID99-IDZRLU4.html?bs=olx_pro_listing 2x Raspberry Pi 3B v1.2 1GB RAM + obudowy: https://www.olx.pl/d/oferta/raspberry-pi-3b-v1-2-1gb-ram-CID99-IDZRLg7.html?bs=olx_pro_listing 2x Raspberry Pi 4B 4GB RAM + obudowy: https://www.olx.pl/d/oferta/2x-raspberry-pi-4b-4gb-ram-CID99-IDZRKs7.html?bs=olx_pro_listing     Na OLX włączony jest zakup z przesyłką, jak wspominałem - ceny są do negocjacji.   
    • @RimciRimci Ok, ale ja w tych wizjach nie widzę opcji "po okresie niedoli Polska dociąga do gospodarczego poziomu relatywnego bogactwa". Wracając do tego, co napisałeś: To wprowadza dysonans. Czy oznacza to że opcja atrakcyjna jest gorsza? No bo najwidoczniej nie jest lepsza.
    • Opisałem teoretyczny przypadek "co gdyby...". Dlatego mówię, że wychodzenie z Unii to mrzonki patrząc jaką pozycję na świecie ma Polska. Tym bardziej przy obecnej sytuacji geopolitycznej.    atrakcyjna = zadowalająca. Gdzie ja napisałeś "bardziej atrakcyjna"? No właśnie... Bardziej atrakcyjna to polski rząd musiałby mieć jakieś haki na Niemców 
  • Aktywni użytkownicy

×
×
  • Dodaj nową pozycję...