Thread hängt nach kurzer Zeit

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
CruzWoman
Beiträge: 3
Registriert: Fr Jun 29, 2012 4:31 pm

Thread hängt nach kurzer Zeit

Beitrag von CruzWoman » Fr Jun 29, 2012 5:16 pm

Hallo,
ich schreibe gerade ein Programm, dass Bilder von der Kinectkamera anzeigen soll. Da ich mit Oop noch nicht viel gemacht habe, tue ich mich ziemlich schwer damit. (Habe zuerst alles in eine Datei geschrieben und das funktioniert auch, nun will ich das ganze kapseln in Klassen)
Bisher sieht mein Programm wie folgt aus: Ich habe eine Hauptklasse mit main, eine Klasse, die mit SDL das Bild anzeigen soll und eine Klasse, die die Bilder von der Kinect holen und dann mit der SDL-Klasse anzeigen soll.
Nun habe ich schon einiges ausprobiert. Zuerst habe ich den Thread in der Kinect Klasse gestartet, dann habe ich das ganze in meiner Hauptklasse in der main versucht. Das Ergebnis ist das selbe. Der Thread (hab's mit WinThreads und SDL_Threads probiert) startet und zeigt auch ein paar Bilder an (beim debuggen in Einzelschritten in VC++ 2010 Express wurden mir ein paar Einzelbilder angezeigt) und dann hängt sich irgendwo was auf und mein Programm kommt zu keinem der gesetzten Breakpoints mehr...?
In der Ausgabe beim Debugging kommt:
Der Thread 'Win32-Thread' (0xedc) hat mit Code 0 (0x0) geendet.
Und dann ist das Bild eingefroren, das Fenster ist also noch offen, aber im Debugger ist "F5 Weiter" ausgegraut. Es geht also nix mehr. Irgendwie scheint sich das Programm selbst zu beenden, aber der Thread, bzw. das SDL-Fenster bleibt noch offen. Ich weiß jetzt gar nicht mehr weiter und weiß auch gar nicht wo ich nach dem Fehler suchen soll. Es wird wohl ein typischer Anfängerfehler sein...?

Ich hoffe irgendjemand sieht wo das Problem liegt.
Vielen Dank schon einmal.


Hier mal der Code:
meine Hauptklasse EarTracker.h

Code: Alles auswählen

#pragma once
#include "ProcessSDL.h"
#include "ShowKinect.h"
#include <SDL_thread.h>

class ProcessSDL;

class EarTracker
{
public:
	SDL_Thread *rgbThread;
	bool sdlQuit;

public:
	EarTracker(void);
	virtual ~EarTracker(void);
	int threadFunctionRGB(void* pthis);
};
EarTracker.cpp

Code: Alles auswählen

#include "EarTracker.h"

EarTracker::EarTracker(void)
{

}


EarTracker::~EarTracker(void)
{

}

int threadFunctionRGB(void* pthis)
{
	return ((ShowKinect*)pthis)->Nui_GotColorAlert();
}

int main(int argc, char* argv[]){
	ProcessSDL *myProcessSDL = new ProcessSDL; //SDL Objekt
	ShowKinect *myShowKinect = new ShowKinect; //Kinect Objekt

	SDL_Thread *rgbThread = NULL;

	int xPos = 0;
	int yPos = 0;

	//Close SDL Window or kill Thread: Wait for quit
	bool sdlQuit = false;

	if (myProcessSDL->initSDL() == false) return 1; //init SDL

	HRESULT hr = myShowKinect->Nui_Init(myProcessSDL); // zero and init Kinect
	if ( FAILED( hr ) )
    {
        MessageBox( NULL, "Could not init Kinect.", NULL, NULL );
        return hr;
    }

	rgbThread = SDL_CreateThread(threadFunctionRGB,myShowKinect);

	while(!sdlQuit && !myShowKinect->quitThread) { //Fenster schließen
		//Do everything here
		while(SDL_PollEvent(&myProcessSDL->event)) {
			if (myProcessSDL->event.type == SDL_QUIT) {
				sdlQuit=true;
				myShowKinect->quitThread = true;
			}
		}

	}
	
	myProcessSDL->quitSDL();
	delete myProcessSDL;
	delete myShowKinect;
	SDL_KillThread( rgbThread );

	return 0;
}

Anzeige des Fenster, ProcessSDL.h

Code: Alles auswählen

#pragma once

#include <SDL.h>

//extern SDL_Surface *m_pScreen;

class ProcessSDL
{
public:
	SDL_Surface *m_pScreen;
	SDL_Event event;

public:
	ProcessSDL(void);
	virtual ~ProcessSDL(void);

	bool initSDL();
	void quitSDL();
	SDL_Surface *GetScreen() {return m_pScreen;}
	bool ShowImageOnScreen(void* buffer, int imageWidth, int imageHeight, int imageDepth, int xPos, int yPos, int myPitch);
};
ProcessSDL.cpp

Code: Alles auswählen

#include "ProcessSDL.h"

ProcessSDL::ProcessSDL(void)
{
	SDL_Surface *m_pScreen;
	m_pScreen = NULL;
}


ProcessSDL::~ProcessSDL(void)
{
}

bool ProcessSDL::initSDL() { 
	//Initialize all SDL subsystems 
	if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) { return false; } 
	//
	atexit(SDL_Quit);
	// init screen
	SDL_putenv("SDL_VIDEO_CENTERED=center");
	SDL_WM_SetCaption("Ear Tracker", NULL);
	m_pScreen = SDL_SetVideoMode( 1280,720, 32, SDL_SWSURFACE); //2 * 640 = 1280 2 Bilder (640 + 480) nebeneinander, 480+240 = 720 1,5 Bilder (640*480 und 320*240) übereinander
	if ( m_pScreen == NULL )
	{
		return false;
	}  
	//If everything initialized fine 
	return true; 
}

void ProcessSDL::quitSDL() { 
	//Free the surfaces  
	SDL_FreeSurface( m_pScreen ); 
	//Quit SDL 
	SDL_Quit(); 
}

bool ProcessSDL::ShowImageOnScreen(void* buffer, int imageWidth, int imageHeight, int imageDepth, int xPos, int yPos, int myPitch)
{
	//SDL_Surface *m_pScreen;
	SDL_Surface *Image;
	Image = (SDL_Surface*)malloc(sizeof(SDL_Surface));
	Image = SDL_CreateRGBSurfaceFrom(buffer,imageWidth,imageHeight,imageDepth,myPitch, 0,0,0,0);

	//Put Picture on Screen
	SDL_Rect sRect; //Quellbereich
	SDL_Rect dRect; //Zielbereich
	// Setzen des Quellbereichs
	sRect.x = 0;
	sRect.y = 0;
	sRect.w = Image->w;  // das gesamte Bildbreite
	sRect.h = Image->h;   // das gesamte Bildhöhe
	
	// Setzen des Zielbereichs
	dRect.x = xPos;
	dRect.y = yPos;
	dRect.w = Image->w;
	dRect.h = Image->h;

	if( SDL_MUSTLOCK( m_pScreen ) ) { SDL_LockSurface( m_pScreen ); }
	//Rectausschnitt des Quellbildes Image auf Rectausschnitt des Screen kopieren
	SDL_BlitSurface(Image, &sRect, m_pScreen, &dRect ); 
	//Update Screen 
	SDL_UpdateRects(m_pScreen,1,&dRect);
	if( SDL_MUSTLOCK( m_pScreen ) ) { SDL_UnlockSurface( m_pScreen ); }
	//Pause 
	SDL_Delay( 1 );
	SDL_FreeSurface(Image);

	return 0;
}
Kinectbild holen ShowKinect.h

Code: Alles auswählen

#pragma once

#include <Windows.h>
#include <NuiApi.h>
#include <stdio.h>
#include "ProcessSDL.h"

class ProcessSDL;

class ShowKinect
{
public: 
	 // thread handling
    HANDLE        m_hThNuiProcess;
    HANDLE        m_hEvNuiProcessStop;

	HANDLE        m_hNextDepthFrameEvent;
    HANDLE        m_hNextColorFrameEvent;
    HANDLE        m_hNextSkeletonEvent;
    HANDLE        m_pDepthStreamHandle;
    HANDLE        m_pVideoStreamHandle;

	HANDLE hColorStreamHandle;
	HANDLE hDepthStreamHandle;
	HANDLE hSkeletonStreamHandle;
	INuiSensor *m_pNuiSensor;
	BSTR m_instanceId;      
	HRESULT hr;
	byte *rgbBuffer;
	int rgbPitch;
	bool canGetRGBFrame;
	bool gotRGBFrame;
	ProcessSDL *p_myProcessSDL;

public:
	int rgbImageWidth;
	int rgbImageHeight;
	int rgbImageDepth;
	bool quitThread;

public:
	ShowKinect(void);
	virtual ~ShowKinect(void);

	void zeroKinect();
	HRESULT Nui_Init( ProcessSDL *myProcessSDL );
	void StartThread();
	void Nui_UnInit( );
	void                    Nui_GotDepthAlert( );
    int                     Nui_GotColorAlert( );
    void                    Nui_GotSkeletonAlert( );
	static DWORD WINAPI     Nui_ProcessThread(LPVOID pParam);
    DWORD WINAPI            Nui_ProcessThread();
	byte *GetRGBFrame() {return rgbBuffer;}
	int GetRGBPitch() {return rgbPitch;}
	bool GetCanGetRGBFrame() {return canGetRGBFrame;}
	void SetCanGetRGBFrame(bool b) {canGetRGBFrame = b;}
	bool GetGotRGBFrame() {return gotRGBFrame;}
	void SetGotRGBFrame(bool b) {gotRGBFrame = b;}

	//friend class EarTracker;
};
ShowKinect.cpp

Code: Alles auswählen

#include "ShowKinect.h"

ShowKinect::ShowKinect(void):rgbImageWidth(640),rgbImageHeight(480),rgbImageDepth(32),canGetRGBFrame(false),gotRGBFrame(true),rgbPitch(0),rgbBuffer(NULL)
{
	ShowKinect::zeroKinect();
}


ShowKinect::~ShowKinect(void)
{
}

void ShowKinect::zeroKinect()
{
	if (m_pNuiSensor)
    {
        m_pNuiSensor = NULL;
    }
    m_hNextDepthFrameEvent = NULL;
    m_hNextColorFrameEvent = NULL;
    m_hNextSkeletonEvent = NULL;
    m_pDepthStreamHandle = NULL;
    m_pVideoStreamHandle = NULL;
    m_hThNuiProcess = NULL;
    m_hEvNuiProcessStop = NULL;
	m_instanceId = NULL;      
	hr = NULL;
	p_myProcessSDL = NULL;
	quitThread = false;
}

HRESULT ShowKinect::Nui_Init( ProcessSDL* myProcessSDL)
{
	p_myProcessSDL = myProcessSDL;

    HRESULT  hr;

    if ( !m_pNuiSensor )
    {
        HRESULT hr = NuiCreateSensorByIndex(0, &m_pNuiSensor);

        if ( FAILED(hr) )
        {
            return hr;
        }

        SysFreeString(m_instanceId);

        m_instanceId = m_pNuiSensor->NuiDeviceConnectionId();
    }

    m_hNextDepthFrameEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
    m_hNextColorFrameEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
    m_hNextSkeletonEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
     
    DWORD nuiFlags = NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX | NUI_INITIALIZE_FLAG_USES_SKELETON |  NUI_INITIALIZE_FLAG_USES_COLOR;
    hr = m_pNuiSensor->NuiInitialize( nuiFlags );
    if ( E_NUI_SKELETAL_ENGINE_BUSY == hr )
    {
        nuiFlags = NUI_INITIALIZE_FLAG_USES_DEPTH |  NUI_INITIALIZE_FLAG_USES_COLOR;
        hr = m_pNuiSensor->NuiInitialize( nuiFlags) ;
    }
  
    if ( FAILED( hr ) )
    {
        if ( E_NUI_DEVICE_IN_USE == hr )
        {
            MessageBox(NULL,"This Kinect sensor is already in use.", NULL,NULL );
        }
        else
        {
            MessageBox( NULL, "Failed to initialize Kinect.", NULL, NULL );
        }
        return hr;
    }

    if ( HasSkeletalEngine( m_pNuiSensor ) )
    {
        hr = m_pNuiSensor->NuiSkeletonTrackingEnable( m_hNextSkeletonEvent, 0 );
        if( FAILED( hr ) )
        {
            MessageBox( NULL, "Could not enable skeleton tracking.", NULL, NULL );
            return hr;
        }
    }

    hr = m_pNuiSensor->NuiImageStreamOpen(
        NUI_IMAGE_TYPE_COLOR,
        NUI_IMAGE_RESOLUTION_640x480,
        0,
        2,
        m_hNextColorFrameEvent,
        &m_pVideoStreamHandle );

    if ( FAILED( hr ) )
    {
        MessageBox( NULL, "Could not open image stream video.", NULL, NULL );
        return hr;
    }

    hr = m_pNuiSensor->NuiImageStreamOpen(
        HasSkeletalEngine(m_pNuiSensor) ? NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX : NUI_IMAGE_TYPE_DEPTH,
        NUI_IMAGE_RESOLUTION_320x240,
        0,
        2,
        m_hNextDepthFrameEvent,
        &m_pDepthStreamHandle );
	
    if ( FAILED( hr ) )
    {
        MessageBox( NULL, "Could not open image stream depth.", NULL, NULL );
        return hr;
    }

    // Start the Nui processing thread
    //m_hEvNuiProcessStop = CreateEvent( NULL, FALSE, FALSE, NULL );
    //m_hThNuiProcess = CreateThread( NULL, 0, Nui_ProcessThread, this, 0, NULL );

    return hr;
}

/*void ShowKinect::StartThread()
{
	// Start the Nui processing thread
    m_hEvNuiProcessStop = CreateEvent( NULL, FALSE, FALSE, NULL );
    m_hThNuiProcess = CreateThread( NULL, 0, Nui_ProcessThread, this, 0, NULL );
}*/

void ShowKinect::Nui_UnInit( )
{
    // Stop the Nui processing thread
    if ( NULL != m_hEvNuiProcessStop )
    {
        // Signal the thread
        SetEvent(m_hEvNuiProcessStop);

        // Wait for thread to stop
        if ( NULL != m_hThNuiProcess )
        {
            WaitForSingleObject( m_hThNuiProcess, INFINITE );
            CloseHandle( m_hThNuiProcess );
        }
        CloseHandle( m_hEvNuiProcessStop );
    }

    if ( m_pNuiSensor )
    {
        m_pNuiSensor->NuiShutdown( );
    }
    if ( m_hNextSkeletonEvent && ( m_hNextSkeletonEvent != INVALID_HANDLE_VALUE ) )
    {
        CloseHandle( m_hNextSkeletonEvent );
        m_hNextSkeletonEvent = NULL;
    }
    if ( m_hNextDepthFrameEvent && ( m_hNextDepthFrameEvent != INVALID_HANDLE_VALUE ) )
    {
        CloseHandle( m_hNextDepthFrameEvent );
        m_hNextDepthFrameEvent = NULL;
    }
    if ( m_hNextColorFrameEvent && ( m_hNextColorFrameEvent != INVALID_HANDLE_VALUE ) )
    {
        CloseHandle( m_hNextColorFrameEvent );
        m_hNextColorFrameEvent = NULL;
    }

    if ( m_pNuiSensor )
    {
        m_pNuiSensor->Release();
        m_pNuiSensor = NULL;
    }
   
}

/*
DWORD WINAPI ShowKinect::Nui_GotVideoAlert(LPVOID pParam)
{
    ShowKinect *pthis = (ShowKinect *) pParam;
    return pthis->Nui_GotVideoAlert();
}*/
DWORD WINAPI ShowKinect::Nui_ProcessThread(LPVOID pParam)
{
    ShowKinect *pthis = (ShowKinect *) pParam;
    return pthis->Nui_ProcessThread();
}

DWORD WINAPI ShowKinect::Nui_ProcessThread()
{
    const int numEvents = 4;
    HANDLE hEvents[numEvents] = { m_hEvNuiProcessStop, m_hNextDepthFrameEvent, m_hNextColorFrameEvent, m_hNextSkeletonEvent };
    int    nEventIdx;

    // Main thread loop
    bool continueProcessing = true;
    while ( continueProcessing )
    {
        // Wait for any of the events to be signalled
        nEventIdx = WaitForMultipleObjects( numEvents, hEvents, FALSE, 100 );

        // Process signal events
        switch ( nEventIdx )
        {
            case WAIT_TIMEOUT:
                continue;

            // If the stop event, stop looping and exit
            case WAIT_OBJECT_0:
                continueProcessing = false;
                continue;

            case WAIT_OBJECT_0 + 1:
                Nui_GotDepthAlert();
                break;

            case WAIT_OBJECT_0 + 2:
                Nui_GotColorAlert();
                break;

            case WAIT_OBJECT_0 + 3:
                Nui_GotSkeletonAlert( );
                break;
        }
    }

    return 0;
}

int ShowKinect::Nui_GotColorAlert( )
{
	while (!quitThread)
	{
		NUI_IMAGE_FRAME imageFrame;

		HRESULT hr = m_pNuiSensor->NuiImageStreamGetNextFrame( m_pVideoStreamHandle, 0, &imageFrame );

		if ( FAILED( hr ) )
		{
			return 1;
		}

		INuiFrameTexture * pTexture = imageFrame.pFrameTexture;
		NUI_LOCKED_RECT LockedRect;
		pTexture->LockRect( 0, &LockedRect, NULL, 0 );
		if ( LockedRect.Pitch != 0 )
		{
			//Show Frame in SDL
			p_myProcessSDL->ShowImageOnScreen(static_cast<BYTE *>(LockedRect.pBits), rgbImageWidth, rgbImageHeight, rgbImageDepth, 0, 0, LockedRect.Pitch);//Pos 0,0 => obere linke Ecke
		}
		else
		{
			OutputDebugString( "Buffer length of received texture is bogus\r\n" );
		}

		pTexture->UnlockRect( 0 );

		m_pNuiSensor->NuiImageStreamReleaseFrame( m_pVideoStreamHandle, &imageFrame );
	}
	return 0;
}

void ShowKinect::Nui_GotDepthAlert( )
{
	//TODO Grab Depth
}

void ShowKinect::Nui_GotSkeletonAlert()
{
	//TODO Grab Skeleton bzw. Headposition
}

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Thread hängt nach kurzer Zeit

Beitrag von Xin » Fr Jun 29, 2012 7:37 pm

Kerli kann da vielleicht spontaner helfen, ich müsste mich da durchdebuggen.

Ansonsten möchte ich Dich bitten, soviele Quellen als Projekt zu verpacken und als .zip hochzuladen.
Kinnect klingt wiederum stark nach XBox - falls ein Kinnect zur Reproduktion erforderlich ist, so habe ich leider keins.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

CruzWoman
Beiträge: 3
Registriert: Fr Jun 29, 2012 4:31 pm

Re: Thread hängt nach kurzer Zeit

Beitrag von CruzWoman » Sa Jun 30, 2012 7:33 am

Hallo,
danke für die Antwort. Habe jetzt ein paarmal probiert das gezippte Projekt hochzuladen. Es klappt aber nicht...
Habe aber in der Zwischenzeit eine "Lösung" gefunden. Und zwar habe ich am Ende der While-Schleife der Threadfunktion Nui_GotColorAlert mal eine MessageBox eingeblendet, dann lief es plötzlich. Dadurch bin ich drauf gekommen, dass es mit der SDL-Wartezeit zusammenhängen könnte. Diese habe ich jetzt erhöht von SDL_Delay(1) auf SDL_Delay(35) und schwups es läuft...
Mein SDL-Funktion, die das Bild anzeigt sieht jetzt so aus:

Code: Alles auswählen

bool ProcessSDL::ShowImageOnScreen(void* buffer, int imageWidth, int imageHeight, int imageDepth, int xPos, int yPos, int myPitch)
{
	//SDL_Surface *m_pScreen;
	SDL_Surface *Image;
	Image = (SDL_Surface*)malloc(sizeof(SDL_Surface));
	Image = SDL_CreateRGBSurfaceFrom(buffer,imageWidth,imageHeight,imageDepth,myPitch, 0,0,0,0);

	//Put Picture on Screen
	SDL_Rect sRect; //Quellbereich
	SDL_Rect dRect; //Zielbereich
	// Setzen des Quellbereichs
	sRect.x = 0;
	sRect.y = 0;
	sRect.w = Image->w;  // das gesamte Bildbreite
	sRect.h = Image->h;   // das gesamte Bildhöhe
	
	// Setzen des Zielbereichs
	dRect.x = xPos;
	dRect.y = yPos;
	dRect.w = Image->w;
	dRect.h = Image->h;

	if( SDL_MUSTLOCK( m_pScreen ) ) { SDL_LockSurface( m_pScreen ); }
	//Rectausschnitt des Quellbildes Image auf Rectausschnitt des Screen kopieren
	SDL_BlitSurface(Image, &sRect, m_pScreen, &dRect ); 
	//Update Screen 
	SDL_UpdateRects(m_pScreen,1,&dRect);
	if( SDL_MUSTLOCK( m_pScreen ) ) { SDL_UnlockSurface( m_pScreen ); }
	//Pause 
	SDL_Delay( 35 );
	SDL_FreeSurface(Image);

	return 0;
}
Allerdings muss ich sagen, dass ich nicht verstehe, dass es mit SDL_Delay(1) in meinem ersten Versuch OHNE Klassen funktioniert und hier (mit Klassen) muss ich die Zeit erhöhen...? Evtl. ist das eher etwas für ein SDL-Forum, aber vielleicht hat hier auch jemand eine Antwort für mich.
Vielen Dank schon mal und viele Grüße

Benutzeravatar
Kerli
Beiträge: 1456
Registriert: So Jul 06, 2008 10:17 am
Wohnort: Österreich
Kontaktdaten:

Re: Thread hängt nach kurzer Zeit

Beitrag von Kerli » Sa Jun 30, 2012 12:14 pm

Ich hab mit SDL Threads noch nichts gemacht, aber wenn unterschiedliches Timing das Problem löst ist es vermutlich ein Synchronisationsproblem. Du solltest einmal bei allen möglichen Ausstiegspunkten einen Text ausgeben, damit du siehst wodurch sich der Thread beendet.

Übrigens:
CruzWoman hat geschrieben: Image = (SDL_Surface*)malloc(sizeof(SDL_Surface));
Image = SDL_CreateRGBSurfaceFrom(buffer,imageWidth,imageHeight,imageDepth,myPitch, 0,0,0,0);
das schaut mir ziemlich nach einem ungewollten Speicherleck aus...
"Make it idiot-proof and someone will invent an even better idiot." (programmers wisdom)

OpenGL Tutorials und vieles mehr rund ums Programmieren: http://www.tomprogs.at

CruzWoman
Beiträge: 3
Registriert: Fr Jun 29, 2012 4:31 pm

Re: Thread hängt nach kurzer Zeit

Beitrag von CruzWoman » Mo Jul 02, 2012 1:12 pm

OK. Ich werde mir das nochmal genauer anschauen.
Vielen Dank.

Antworten