Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[SDL] Multithreading do wyświetlania paska ładowania

Ostatnio zmodyfikowano 2012-07-11 10:02
Autor Wiadomość
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:
C/C++
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:
C/C++
//globalne

int proc_ladowania; //procent ładowania
bool ladowanie = false; //true, jeśli zacznie się ładować
SDL_Thread * watek_wczytywania = NULL;

int render_paska( void * data ) {
   
    while( ladowanie == true ) { //tylko jeśli program zacznie wczytywać dane
        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 ) {
    //std::cout << "Wczytywanie mapy..." << std::endl;
   
    watek_wczytywania = SDL_CreateThread( render_paska, NULL ); //uruchomienie wątku
   
   
   
    int wczytana_dana;
   
    ladowanie = true; //zaczynamy ładowanie - start wyświetlania paska w innym threadzie
    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;
           
            //jakies funkcje do wczytywania fstream
           
            dane_mapy.push_back( wczytana_dana ); //uzupełnienie wektora
           
            proc_ladowania =(( double ) numer /( mapa_w_kafle * mapa_h_kafle ) ) * 100; //obliczenie procentu ładowania
        }
       
    }
    ladowanie = false; //koniec odliczania
   
    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
P-59745
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).
P-59749
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?
C/C++
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 );
    }
}
P-59752
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.

:)
P-59761
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ś.
P-59762
waxx
» 2012-07-10 19:28:30
A co za problem odpalic 2 watek do wczytywania zasobow?
P-59806
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.
P-59825
« 1 »
  Strona 1 z 1