[SFML] MultiThreading z biblioteką
Ostatnio zmodyfikowano 2012-04-22 20:21
Admixior Temat założony przez niniejszego użytkownika |
[SFML] MultiThreading z biblioteką » 2012-04-22 19:17:32 Witam. Pisza aplikację która będzie robiła coś takiego... 1 thread: wyświetla obraz i zajmuje się innymi sprawami kosmetycznymi. 2 thread: pobiera obraz z kamery i zapisuje go do sf::Image.
Globalnie są zdefiniowane 2 obiekty sf::Image obraz[2]; Gdy w 1 threadzie wyświetlam obraz[0]; w 2 threadzie chcę ładować obraz[1];. Niestety podczas ładowania w 2 threadzie obraz[1].LoadFromPixels(...); w 1 threadzie wykonuje się m.in. funkcja wnd.Display(); I oczywiście wychodzi błąd, że próbuje uzyskać dostęp do nie istniejącego adresu. Nie wiem czy to jest wina OpenGL-a czy moja. W innym projekcie próbowałem robić w ten sam sposób aż w końcu zrezygnowałem. Ale tutaj takie coś jest nie możliwe. Co mogę zrobić żeby nie wychodził błąd.
PS. W razie "w" mogę podrzucić kod. |
|
DejaVu |
» 2012-04-22 19:28:17 Poczytaj o sekcjach krytycznych. W trakcie kopiowania obrazka, dostęp do niego powinien mieć tylko i wyłącznie jeden wątek.
Czyli: thread renderujący powinien:
Thread generujący obrazek (kamera) powinien:
Czyli:
sf::Image imageCamera; sf::Image imageTransfer; sf::Image imageRenderer;
|
|
Admixior Temat założony przez niniejszego użytkownika |
» 2012-04-22 19:49:43 Właściwie nie wiem czy tak można jak ja zrobiłem ale po części oddaje sens. Obrazki są na przemian używane w threadzie. Nie wiem czy tak można. Ale wg poniższego kodu nigdy nie powinno się zdarzyć że naraz obie funkcje mają dostęp do jednego obrazka. Zamieściłem kod bo mogłem też ja coś zepsuć. int zrobione =- 1; Image obrazek[ 2 ];
int nr_obrazu =- 1; Sprite kamera; for( bool cont = true; cont && wnd.IsOpened(); ) { while( wnd.GetEvent( zdarzenie ) ) { if( zdarzenie.Type == Event::MouseButtonPressed ) { cont = false; } else if( zdarzenie.Type == sf::Event::Closed ) { wnd.Close(); } } if( nr_obrazu != zrobione ) { kamera.SetImage( obraz[ nr_obrazu = zaladowane ] ); zrobione =- 1; } wnd.Draw( kamera ); wnd.Display(); }
UINT LadowanieObrazuZKamery( LPVOID * cp ) { int CAMERA_WIDTH = 1600, CAMERA_HEIGHT = 900; cv::VideoCapture cap( 0 ); if( !cap.isOpened() ) { obraz_z_kamery = false; return - 1; } else { cap.set( CV_CAP_PROP_FRAME_WIDTH, CAMERA_WIDTH ); cap.set( CV_CAP_PROP_FRAME_HEIGHT, CAMERA_HEIGHT ); CAMERA_WIDTH = cap.get( CV_CAP_PROP_FRAME_WIDTH ); CAMERA_HEIGHT = cap.get( CV_CAP_PROP_FRAME_HEIGHT ); cap.set( CV_CAP_PROP_FPS, 25 ); cap.set( CV_CAP_PROP_CONVERT_RGB, 0 ); obraz_z_kamery = true; } char * rgba_data = new char[ CAMERA_HEIGHT * CAMERA_WIDTH * 4 ]; cv::Mat image_cam; kamera.SetScale( 1024.f / CAMERA_WIDTH, 768.f / CAMERA_HEIGHT ); int x = 0; while( !stop_all ) { while( zaladowane !=- 1 ) sf::Sleep( 0.01f ); if( x == 2 ) x = 0; cap.read( image_cam ); conv_rgb2rgba(( uchar * ) image_cam.data, rgba_data, CAMERA_HEIGHT * CAMERA_WIDTH ); obraz[ x ].LoadFromPixels( CAMERA_WIDTH, CAMERA_HEIGHT,( Uint8 * ) rgba_data ); zaladowane = x; x++; } delete[] rgba_data; return 0; }
|
|
DejaVu |
» 2012-04-22 19:54:12 Nie ma takiej opcji żeby działał Ci kod prawidłowo bez sekcji krytycznych. |
|
Admixior Temat założony przez niniejszego użytkownika |
» 2012-04-22 20:03:40 heh... A jednak znalazłem błąd. W funkcji renderującej zamiast
if(nr_obrazu!=zaladowane)
powinno być if(nr_obrazu!=zaladowane && zaladowane!=-1)
Dlaczego? Wystarczy zobaczyć na ciało if'a.
Funkcja pobierająca obraz z kamery trwa trochę dłużej więc próbowało odwołać się do obraz[-1]. Kolejny głupi błąd związany z tym projektem. ARGH.... |
|
DejaVu |
» 2012-04-22 20:13:25 Nadal podtrzymuję swoją wersję :)
PS. Spróbuj przeciągnąć okno aplikacji ;p |
|
Elaine |
» 2012-04-22 20:21:51 Nie ma takiej opcji żeby działał Ci kod prawidłowo bez sekcji krytycznych. |
Jeśli kopiować wskaźnik do obrazka, a nie cały obrazek, to sekcja krytyczna nie będzie potrzebna, wystarczy CAS. Martwić się wtedy można o muteks na new i delete, ale one zajmują znacznie mniej czasu niż kopiowanie dużej tablicy, w przypadku kopiowania obrazka i tak mogą zostać wywołane, a w dobrym wielowątkowym alokatorze (do których HeapAlloc się nie zalicza) walka o ten muteks nie będzie problemem. |
|
« 1 » |