mostrom Temat założony przez niniejszego użytkownika |
[SDL] Multithreading do wyświetlania paska ładowania » 2012-07-09 16:55:21 Witam. Napisałem sobie edytor mapy kafelkowej. Mapa zapisuje się w pliku binarnie, żeby jak najbardziej skrócić czas odczytu. Przy uruchomieniu programu te dane są wczytywane do wektora. Przy mapach tak 1000x1000 kafelków, wektor zapełnia się momentalnie, ale przy 10000 x 10000 ten czas oczywiście wielokrotnie się zwiększa. Podczas tego ładowania chciałem na ekranie wyświetlić pasek ładowania. Oto moja klasa paska: class LoadBar { public: LoadBar( SDL_Surface * grafika_paska, int rzm ); ~LoadBar() { SDL_FreeSurface( graf_progres ); } void pokaz_proc( SDL_Surface *, int x, int y, int procent ); private: SDL_Surface * _graf_progres; int _dlugosc; double _procent; };
void LoadBar::pokaz_proc( SDL_Surface * scr, int x, int y, int procent ) { SDL_Rect cel; int max = procent * _procent; for( int i = 0; i < max; i++ ) { cel.x = x + i; cel.y = y; SDL_BlitSurface( _graf_progres, NULL, scr, & cel ); } }
No i przy renderowaniu paska podczas uzupełniania wektora, czas znowu się wydłuża. Dlatego zastanawiałem się nad umieszczeniem renderowania w innym wątku. Pierwszy raz używałem funkcji do obsługi wielu wątków. Oto co mam:
int proc_ladowania; bool ladowanie = false; SDL_Thread * watek_wczytywania = NULL;
int render_paska( void * data ) { while( ladowanie == true ) { SDL_Surface * graf_pas = IMG_Load( "grafika/load.bmp" ); LoadBar pasek( graf_pas, 860 ); pasek.pokaz_proc( ekran, 20, 20, proc_ladowania ); SDL_UpdateRect( ekran, 20, 20, 860, 50 ); SDL_FreeSurface( graf_pas ); } } void wczytaj_mape_z_pliku( std::istream & mapa ) { watek_wczytywania = SDL_CreateThread( render_paska, NULL ); int wczytana_dana; ladowanie = true; for( int i = 0; i < mapa_h_kafle; i++ ) { for( int j = 0; j < mapa_w_kafle; j++ ) { int numer = i * mapa_w_kafle + j; dane_mapy.push_back( wczytana_dana ); proc_ladowania =(( double ) numer /( mapa_w_kafle * mapa_h_kafle ) ) * 100; } } ladowanie = false; std::cout << "Wczytano mape o wymiarach: " << mapa_w_kafle << " x " << mapa_h_kafle << std::endl; SDL_KillThread( watek_wczytywania ); }
No i niby działa jak powinno, ale przy przesunięciu okna SDL, pasek zawiesza się (okno ma brak odpowiedzi pod win7), ale dane są cały czas zczytywane. To, że nic z oknem nie można zrobić trochę przeszkadza. Jak rozwiązać tą kwestię? Z góry dzięki |
|
DejaVu |
» 2012-07-09 18:16:28 Odradzam Ci programowanie wielowątkowe tam gdzie nie jest to konieczne (a tu nie jest to konieczne). Zrób najpierw dobrą grę, a potem martw się aby zasoby były szybciej wczytywane.
/edit:
Założę się, że nie zrobisz gry, która będzie działała dobrze z mapą o rozmiarze 10k x 10k, ponieważ to daje 100 mln obiektów na scenie, co daje 95MB zużycia pamięci przy założeniu, że jeden obiekt = 1 bajt (co jest niemożliwe). |
|
mostrom Temat założony przez niniejszego użytkownika |
» 2012-07-09 18:39:05 Dzięki za odpowiedź. Skoro tak się rzeczy mają, to kod wyświetlający pasek ładowania, nawet jeśli ma działać wolno, musi wyglądać tak? vector < int > dane_mapy; int wczytana_dana; for( int i = 0; i < mapa_h_kafle; i++ ) { for( int j = 0; j < mapa_h_kafle; j++ ) { dane_mapy.push_back( wczytana_dana ); SDL_BlitSurface( pasek_ ł adowania, NULL, ekran, & rect ); } }
|
|
m4tx |
» 2012-07-09 20:55:25 Akurat jeśli chodzi o te wszystkie progressbary, to 2 wątek JEST konieczny. Sam pamiętam, jak jeszcze WinAPI robiłem progressbar w jednym wątku - nie dość, że kilkukrotnie wzrastał czas wczytywania, to jest progressbar nie wyglądał tak jak powinien - migał. Chociaż co do tego drugiego nie jest pewien czy to wina jednego wątku, anyway - w Javie zrobiłem to na dwóch wątkach i było już ok. Zrobiłem to na dwóch wątkach, w aplikacji desktopowej i w grze. I było ok. http://www.jmonkeyengine.org/wiki/doku.php/jme3:advanced:loading_screen: There are 3 main ways to update a progress bar. To understand why these methods are necessary, an understanding of the graphics pipeline is needed.
Something like this in a single thread will not work: [...] If you do all of this in a single frame, then it is sent to the graphics card only after the whole code block has executed. By this time the bar has reached 100% and the game has already begun – for the user, the progressbar on the screen would not have visibly changed.
The 2 main good solutions are:
Updating explicitly over many frames Multi-threading | http://docs.oracle.com/javase/tutorial/uiswing/components/progress.html: The instance invokes the doInBackground in a separate thread. This is where the long-running task is actually executed. Using a background thread instead of the event-dispatching thread prevents the user interface from freezing while the task is running. |
:) |
|
DejaVu |
» 2012-07-09 21:05:56 Akurat jeśli chodzi o te wszystkie progressbary, to 2 wątek JEST konieczny.
|
Nie jest konieczny :) Jeżeli coś Ci mrugało to tylko i wyłącznie dlatego, że źle kod napisałeś. |
|
waxx |
» 2012-07-10 19:28:30 A co za problem odpalic 2 watek do wczytywania zasobow? |
|
mostrom Temat założony przez niniejszego użytkownika |
» 2012-07-11 10:02:00 Wczytania zasobów, czyli że w drugim wątku zapełniam wektor danymi, a pasek wyświetla się w tym podstawowym? Myślałem nad tym, jak dokończę kilka niezbędnych rzeczy, to się zabiorę za wczytywanie mapy. |
|
« 1 » |