Problem mit Threads

Luis Felger

Grünschnabel
Hallo, ich versuche jetzt schon 2 - 3 Stunden lang eine Lösung für folgendes Problem zu finden:

Ich versuche mit einem Thread:
Code:
unsigned long threadId;
HANDLE hThread = CreateThread(NULL, 2000, (LPTHREAD_START_ROUTINE)run_screen,(device, device->getTexture("data/graphics/2d/menu.png")), NULL, &threadId);

diese Funktion zu starten:
Code:
void run_screen(void *device, void *texture)
{
	_video *dev = (_video*)device;

	dev->draw2DImage((irr::video::ITexture*)texture, irr::core::rect<irr::s32>(80, 100, 580, 200), irr::core::rect<irr::s32>(80, 100, 580, 200), 0, 0, true);
}

Beim Compilern entstehen noch keine Problem, aber so bald das Programm gestartet werden soll, sagt mir die Console vom MS Visual Studio 2010 folgendes:

Code:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

Ich hab' auch schon mit Google danach gesucht, aber dort hab' ich auch nichts hilfreiches gefunden.

Ach ja, der Bug liegt bei folgender Zeile:

Code:
dev->draw2DImage((irr::video::ITexture*)texture, irr::core::rect<irr::s32>(80, 100, 580, 200), irr::core::rect<irr::s32>(80, 100, 580, 200), 0, 0, true);

(Das ganze wird mit Irrlich programmiert.)
 
Lass uns mal kurz einen Blick auf den Funktionsprototypen werfen:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms682453%28v=vs.85%29.aspx hat gesagt.:
HANDLE WINAPI CreateThread(
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in SIZE_T dwStackSize,
__in LPTHREAD_START_ROUTINE lpStartAddress,
__in_opt LPVOID lpParameter,
__in DWORD dwCreationFlags,
__out_opt LPDWORD lpThreadId
);

Und jetzt, wie du es aufrufst:

Code:
CreateThread(
  NULL,
  2000,
  (LPTHREAD_START_ROUTINE)run_screen,
  (device, 
   device->getTexture("data/graphics/2d/menu.png")),
  NULL,
  &threadId);

Fällt dir da was auf?

1. Du übergibst 7 Parameter an eine Funktion, die nur 6 Parameter erwartet. Du machst das, weil deine LPTHREAD_START_ROUTINE zwei Parameter erwartet. Aber eigentlich darf die laut Dokumentation auch nur einen Parameter akzeptieren:

http://msdn.microsoft.com/de-de/library/aa964928.aspx hat gesagt.:
typedef DWORD (__stdcall *LPTHREAD_START_ROUTINE) (
[in] LPVOID lpThreadParameter
);

Wie das Problem lösen?

Du erstellst eine Struktur, die einen void-Zeiger für den device-Parameter und einen void-Zeiger für den texture-Parameter aufnehmen kann. Dann übergibst du den Zeiger auf die Struktur an CreateThread().

2. Du hältst die Konventionen für Datentypen nicht ein. Bei dwCreationFlags übergibst du NULL, das ist aber gar kein Zeiger. Übergeb doch besser 0.

3. Du erstellst da eine unsigned long-Variable für die Thread-ID, CreateThread erwartet aber DWORD (was prinzipiell auf 32Bit-Systemen das gleiche ist). Aber es hat einen Grund, warum MS sich da entschieden hat, einen Non-Standard-Datentypen einzuführen und den sollte man auch verwenden.
 
Hallo Luis,

ich bin zwar nicht ganz mit "rohen" WinAPI-Threads vertraut, aber ich glaube die Thread-Funktion darf nur einen Parameter (und zwar vom Typ LPVOID) besitzen.

Versuche mal folgendes:
C++:
// Die Irrlicht-Datentypen sollten stimmen,
// zumindest die Namen...
struct TThreadData
{
  irr::IrrlichtDevice *device;
  const char *textureName;
};

DWORD WINAPI run_screen(LPVOID lpParam)
{
  TThreadData myData = *((TThreadData*)lpParam);

  irr::IrrlichtDevice *myDevice = myData.device;
  irr::video::ITexture myTexture = myDevice->getTexture(myData.textureName);

  _video *dev = (_video*)myDevice;

  dev->draw2DImage(myTexture, irr::core::rect<irr::s32>(80, 100, 580, 200), irr::core::rect<irr::s32>(80, 100, 580, 200), 0, 0, true);

  return 0;
}

/* Let's start the thread */
DWORD threadId;
TThreadData theData = {device, "data/graphics/2d/menu.png"};
HANDLE hThread = CreateThread(NULL, 2000, run_screen, &theData, 0, &threadId);
 
Dann klicke bitte auf den Haken neben dem Auf Thema antworten-Button, damit das Thema als erledigt gekennzeichnet wird ;)
 
Zurück