JLI Spieleprogrammierung Foren-Übersicht JLI Spieleprogrammierung

 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen 
 medals.php?sid=1a8d1ce51715ed0627dadd82ded179bbMedaillen   RegistrierenRegistrieren   ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

WINAPI+Multithreading

 
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
The Lord of Programming
Living Legend


Alter: 37
Anmeldedatum: 14.03.2003
Beiträge: 3122

Medaillen: Keine

BeitragVerfasst am: 23.04.2006, 12:52    Titel: WINAPI+Multithreading Antworten mit Zitat

Hi,

ich experimentiere gerade mit Threads herum, komme aber irgendwie zu keinem nennenswerten Ergebnis.
Das Programm arbeitet die Nachrichten über GetMessage() ab. Teil des Programms ist ein Fenster, das Webcam-Vorschau&Aufnahmen durchführen kann. Das eigentliche Problem bzw. der Grund, weswegen ich Multithreading überhaupt einsetzen wollte, ist eine zu träge und teilweise verzögerte Aufnahme über dieses Fenster.

Nun habe ich das versucht, aber es ändert sich entweder nichts oder ich bekomme durch Asynchronisation Fehler. Diese ließen sich zwar beheben, aber das blöde ist, dass sich nichts an der Aufnahme ändert.

Vielleicht habe ich das auch irgendwie falsch aufgebaut/verwaltet. Ich habe noch nie mit Threads gearbeitet und kann auch aus Tutorials nicht so recht herauslesen, wie man so etwas bei Programmen mit Nachrichtenschleifen realisiert.
Hier mal, wie ich das aufgebaut habe(fehlen natürlich noch die jeweiligen CloseHandle() für die Threads Wink ):


CPP:
/***************************
[[[ Hauptthread fürs Programm&Nachrichtenverarbeitung ]]]
***************************/

DWORD WINAPI MainThread(LPVOID Data)
{
   //[...] alles mögliche...Fenster erstellen, Initalisierungsarbeit, ...
   while(GetMessage(&_gui::message,0,0,0)>0)
   {
      TranslateMessage(&_gui::message);
      DispatchMessage(&_gui::message);
   }
   return (DWORD)Data;
}

CPP:
/***************************
[[[ Nebenthread für Aufnahme ]]]
***************************/

DWORD WINAPI CaptureThread(LPVOID Data)
{
   //Aufnahme soll _jetzt_ gestartet werden
   if(_threads::capture_now)
   {
      //Aufnahme starten, blabla...
      //[...]

      //Aufnahme bereits gestartet->nicht mehr nötig
      _threads::capture_now=false;
   }

   return (DWORD)Data;
}

CPP:
/***************************
[[[ WinMain - Start des Hauptthreads ]]]
***************************/

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
   //HAUPTTHREAD erstellen
   _threads::mainthread=CreateThread(NULL,0,MainThread,(LPVOID)1,0,&_threads::main_id);

   //Dessen Priorität hoch setzen
   SetThreadPriority(_threads::mainthread,THREAD_PRIORITY_HIGHEST);

   //Warten, bis Hauptprozess beendet wurde
   WaitForSingleObject(_threads::mainthread,INFINITE);

   return _gui::message.wParam;
}

CPP:
/***************************
[[[ WM-Handler des Hauptfensters ]]]
***************************/

case IDC_REC:
   //Wenn noch nicht aufgenommen wird
   if(!_gui::recording)
   {
      //Aufnehmen
      _gui::recording=true;
      //[...]blabla

      //Wenn anderer Thread gestartet wird SOFORT aufnehmen
      _threads::capture_now=true;

      //NEBENTHREAD für Aufnahme erstellen
      _threads::capturethread=CreateThread(NULL,0,CaptureThread,(LPVOID)2,0,&_threads::capture_id);
   }
   break;

_________________
www.visualgamesentertainment.net
Current projects: RDTDC(1), JLI-Vor-Projekt, Tetris(-Tutorial), JLI-Format
(1) Realtime Developer Testing and Debugging Console


Anschlag, Anleitung zum Atombombenbau, Sprengkörper...
Hilf Schäuble! Damit er auch was findet...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
Dragon
Super JLI'ler


Alter: 38
Anmeldedatum: 24.05.2004
Beiträge: 340
Wohnort: Sachsen
Medaillen: Keine

BeitragVerfasst am: 23.04.2006, 13:58    Titel: Antworten mit Zitat

Warum startest du für die nachrichtenbearbeitung einen eigenen Thread? Der ist doch total überflüssig. Die WinMain ist doch auch nur ein Thread. Warum nicht da rein. Kleiner Tipp, du kannst einen Parameter übergeben. Ich hab mal eine Threadklasse geschrieben, bzw. abgeklaut ^^, naja vieleicht hilft es dir was.

Code:
#include <windows.h>


class Thread
{
public:
   Thread();
   ~Thread();

   bool start();
   virtual int run();

private:
   HANDLE hThread;
};


Code:
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
   Thread* thread = reinterpret_cast<Thread*>(lpParam);
   return thread->run();
}

Thread::Thread() : hThread(NULL)
{
}

Thread::~Thread()
{
   CloseHandle(hThread);
}

bool Thread::start()
{
   DWORD threadid;

   //Wenn bereits eine Instanz existieren, dann false zurückgeben
   if(hThread)
      return false;

   //Den Thread starten
   hThread = CreateThread(NULL, 0, ThreadProc, this, 0, &threadid);
   return hThread != NULL;
}

int Thread::run()
{
   return 0;
}


Ich hab damit nur rumexperimentiert, und ich mit sicherheit nicht fehlerfrei. Vieleicht kannst du damit was anfangen.
_________________
Nur wenn man ein Ziel sieht, kann man es auch treffen.
___________
Mein Leben, Freunde und die Spieleentwicklung
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
FH
Super JLI'ler


Alter: 36
Anmeldedatum: 16.10.2004
Beiträge: 438

Medaillen: Keine

BeitragVerfasst am: 23.04.2006, 15:00    Titel: Antworten mit Zitat

Erstmal: Bei Treads ist die synchronisation extrem wichtig! In diesem Punkt sind CRITICAL_SECTIONs zu erwähnen.
Zu dem Fehler: Ich weiß nicht, ob es so gesund ist, ein Fenster zu verändern, dass von einem anderen Thread verwaltet wird. Der Rest sieht so eigentlich ganz gesund aus.
Noch ein bisschen was anderes:
1.: Das if im CaptureThread sieht ziemlich sinnlos aus.
2.: Die WinMain ist auch nur ein Thread. Du kannst sie getrost als MainThread verwenden.
Gruß

FH
_________________
goto work, send your kids to school
follow fashion, act normal
walk on the pavement, watch T.V.
save for your old age, obey the law
Repeat after me: I am free
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
The Lord of Programming
Living Legend


Alter: 37
Anmeldedatum: 14.03.2003
Beiträge: 3122

Medaillen: Keine

BeitragVerfasst am: 23.04.2006, 21:48    Titel: Antworten mit Zitat

Danke Smile

Also brauche ich manuell nur einen Thread zu erstellen, weil die WinMain selbst schon einer ist?

FH hat Folgendes geschrieben:
1.: Das if im CaptureThread sieht ziemlich sinnlos aus.

Das sieht nur so aus...ich nehme hier nicht manuell auf, sondern verwende dafür vorgesehene Funktionen, die eben das Starten&Stoppen der Aufnahme umfassen. Die Aufnahme selbst läuft automatisch ab bzw. ich habe (oder nehme) keinen Einfluss darauf Wink
Oder wäre es unter diesen Umständen evtl. nötig, dass ich das Capture-Fenster auch in dem separaten Thread erstelle? Confused
_________________
www.visualgamesentertainment.net
Current projects: RDTDC(1), JLI-Vor-Projekt, Tetris(-Tutorial), JLI-Format
(1) Realtime Developer Testing and Debugging Console


Anschlag, Anleitung zum Atombombenbau, Sprengkörper...
Hilf Schäuble! Damit er auch was findet...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
The Lord of Programming
Living Legend


Alter: 37
Anmeldedatum: 14.03.2003
Beiträge: 3122

Medaillen: Keine

BeitragVerfasst am: 24.04.2006, 18:21    Titel: Antworten mit Zitat

Hmm...hab jetzt mal den einen Thread weggelassen und die Nachrichtenschleife in der WinMain gelassen. Viel geändert hat sich dadurch allerdings nicht =/

Ich habe schon mit SetThreadPriority() und verschiedenen Proritäten herumgespielt, aber das Programm verhält sich im Prinzip so, als hätte ich niemals einen zweiten Thread gestartet. Soll heißen, während der Aufnahme kann ich die restlichen Bedienelemente(Buttons, etc...) vergessen, weil sie einfach kaum reagieren...
Was mich noch wundert: Obwohl ich auch mal beide Threads auf THREAD_PRIORITY_TIME_CRITICAL gesetzt habe, zeigt die CPU-Belastung keine Anzeichen von Änderung, sondern bleibt nach wie vor relativ niedrig. Gibt es da keine Möglichkeit, sich mehr "Rechte" von der CPU zu holen? o_O
Oder gibt es irgendetwas, was verursachen könnte, dass die Threads nicht als solche agieren?
_________________
www.visualgamesentertainment.net
Current projects: RDTDC(1), JLI-Vor-Projekt, Tetris(-Tutorial), JLI-Format
(1) Realtime Developer Testing and Debugging Console


Anschlag, Anleitung zum Atombombenbau, Sprengkörper...
Hilf Schäuble! Damit er auch was findet...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
FH
Super JLI'ler


Alter: 36
Anmeldedatum: 16.10.2004
Beiträge: 438

Medaillen: Keine

BeitragVerfasst am: 24.04.2006, 20:18    Titel: Antworten mit Zitat

Es ist nicht ganz so einfach, mit der TIME_CRITICAL. Erstmal ist es gefährlich! Der Thread gibt keine/kaum noch Rechenleistung mehr ab, es sei denn, man zwingt ihn explizit dazu (Sleep()). Das führt bis zum Ausfall der Maus. Allerdings hast du dafür noch was vergessen:
Setz deinen kompletten Prozess SetPriorityClass auf eine höhere Prioritätsklasse (ich würde HIGH_PRIORITY_CLASS nehmen).
Gruß

FH
_________________
goto work, send your kids to school
follow fashion, act normal
walk on the pavement, watch T.V.
save for your old age, obey the law
Repeat after me: I am free
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
The Lord of Programming
Living Legend


Alter: 37
Anmeldedatum: 14.03.2003
Beiträge: 3122

Medaillen: Keine

BeitragVerfasst am: 24.04.2006, 20:52    Titel: Antworten mit Zitat

Das hab ich auch schon versucht (sogar mit REALTIME_PRIORITY_CLASS), aber tut sich anscheinend nichts o_O

Wenn ich die Aufnahme starte, sieht der wichtige Code aktuell so aus:
CPP:
//WinMain-"Thread"
SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_HIGHEST);
SetPriorityClass(GetCurrentThread(),HIGH_PRIORITY_CLASS);

//Neuen Thread erstellen
_threads::capturethread=CreateThread(NULL,0,CaptureThread,(LPVOID)_gui::main_dialog,0,&_threads::capture_id);

//Einstellungen des neuen Threads
SetThreadPriority(_threads::capturethread,THREAD_PRIORITY_HIGHEST);
SetPriorityClass(_threads::capturethread,HIGH_PRIORITY_CLASS);

_________________
www.visualgamesentertainment.net
Current projects: RDTDC(1), JLI-Vor-Projekt, Tetris(-Tutorial), JLI-Format
(1) Realtime Developer Testing and Debugging Console


Anschlag, Anleitung zum Atombombenbau, Sprengkörper...
Hilf Schäuble! Damit er auch was findet...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
FH
Super JLI'ler


Alter: 36
Anmeldedatum: 16.10.2004
Beiträge: 438

Medaillen: Keine

BeitragVerfasst am: 25.04.2006, 08:20    Titel: Antworten mit Zitat

SetPriorityClass wirkt auf den aktuellen Prozess! Nicht Thread!
Du musst also schreiben:
SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
Dann müsste es besser gehen...
Im übrigen is beim VC++ 6.0 ein nützliches Tool namens ProzessViewer dabei, damit kannst du prüfen, ob die Prioritäten korrekt gesetzt wurden.
Gruß

FH
_________________
goto work, send your kids to school
follow fashion, act normal
walk on the pavement, watch T.V.
save for your old age, obey the law
Repeat after me: I am free
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Dragon
Super JLI'ler


Alter: 38
Anmeldedatum: 24.05.2004
Beiträge: 340
Wohnort: Sachsen
Medaillen: Keine

BeitragVerfasst am: 25.04.2006, 13:08    Titel: Antworten mit Zitat

Ich glaube die Priorität eines Threads ist der falsche Ansatz. Da sollte man GAR NICHTS ändern.

Wie nimmst du eigentlich das Bild auf bzw. gibst es auf dem Bildschirm aus. Vieleicht könntes du dazu noch einen Pseudocode machenn
_________________
Nur wenn man ein Ziel sieht, kann man es auch treffen.
___________
Mein Leben, Freunde und die Spieleentwicklung
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
The Lord of Programming
Living Legend


Alter: 37
Anmeldedatum: 14.03.2003
Beiträge: 3122

Medaillen: Keine

BeitragVerfasst am: 25.04.2006, 14:40    Titel: Antworten mit Zitat

Okay, ich werds mal mit dem Prozess selbst versuchen.

Der Pseudocode von der Aufnahme entspricht in etwa dem, was man in den Kommenaren oben auch lesen kann - ist keine große Sache. Wenn mans linear (d.h. ohne Startbutton, etc... mit sofortigem Start) aufbauen würde, sähe es ungefähr so aus(s. unten).

Was ich noch komisch finde, ist (s. Markierung), dass wenn der Flag fYield gesetzt wird, der Aufnahmevorgang schon in einem separaten Thread startet. (Ob ich da allerdings Zugriff darauf bekomme...who knows...?)
Das Problem jedenfalls: Die im ersten Post beschriebenen Symptome(Verzögerung, niedrige FPS, dadurch schlechte Aufnahme). Auffallend ist hierbei, dass die CPU Belastung bei ca. 15% ist. Öffne ich über den Windowsexplorer die Webcam(wird als eigenes Laufwerk aufgeführt) und lasse sie dort laufen, so ist 1. das Bild flüssiger und 2. die CPU Belastung steigt auf über 20%.
Deshalb auch die ganzen Verrenkungen hier mit eigenen Threads. Es wäre einfach wünschenswert, wenn die Webcam sich während der Aufnahme nicht so in der CPU-Belastung zurückhält auf Kosten einer schlechten Aufnahme.


CPP:
/********************************************************************
[[[ Fenster für Capturing erstellen ]]]
*********************************************************************/

_capture::window_capture=capCreateCaptureWindow("Capture Window", WS_CHILD|WS_VISIBLE,
         0,0,
         320, 240,
         _gui::main_dialog,1);

if(_capture::window_capture)
{
   //Fenster mit dem verfügbaren Device verbinden
   if(capDriverConnect(_capture::window_capture,0))
   {
      //EINSTELLUNGEN
      /********************************************************************
      [[[ Fähigkeiten des Capturegeräts abfragen ]]]
      *********************************************************************/

      if(!capDriverGetCaps(_capture::window_capture,&capturecaps,sizeof(CAPDRIVERCAPS)))
      {
         //Fehler
      }

      //Falls möglich, Overlay aktivieren => Hardwarebeschleunigung
      if(capturecaps.fHasOverlay) capOverlay(_capture::window_capture,TRUE);

      //Video auf Fenstergröße skalieren
      SendMessage(_capture::window_capture,WM_CAP_SET_SCALE,TRUE,0);

      //FPS der Vorschau setzen
      capPreviewRate(_capture::window_capture, 1.0e3/29.0);


      //Vorschau laufen lassen
      capPreview(_capture::window_capture,TRUE);


      /********************************************************************
      [[[ Sequence-Einstellungen ]]]
      *********************************************************************/

      capCaptureGetSetup(_capture::window_capture,&_capture::capture_params,sizeof(CAPTUREPARMS));

      //Framerate auf 29 FPS festlegen
      _capture::capture_params.dwRequestMicroSecPerFrame = (DWORD) (1.0e6/29.0);

      //Video als Hintergrundprozess capturen
      _capture::capture_params.fYield=TRUE;

      _capture::capture_params.fAbortLeftMouse=TRUE;
      _capture::capture_params.fAbortRightMouse=TRUE;
      _capture::capture_params.fStepCaptureAt2x=FALSE;

      capCaptureSetSetup(_capture::window_capture,&_capture::capture_params,sizeof(CAPTUREPARMS));
   }
}

/********************************************************************
[[[ Aufnahme starten ]]]
*********************************************************************/

//Outputdatei festlegen
capFileSetCaptureFile(_capture::window_capture,"capture.avi");

//50 MB reservieren
capFileAlloc(_capture::window_capture,(1024L * 1024L * 50));

//Aufnahme starten
capCaptureSequence(_capture::window_capture);

_________________
www.visualgamesentertainment.net
Current projects: RDTDC(1), JLI-Vor-Projekt, Tetris(-Tutorial), JLI-Format
(1) Realtime Developer Testing and Debugging Console


Anschlag, Anleitung zum Atombombenbau, Sprengkörper...
Hilf Schäuble! Damit er auch was findet...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
FH
Super JLI'ler


Alter: 36
Anmeldedatum: 16.10.2004
Beiträge: 438

Medaillen: Keine

BeitragVerfasst am: 25.04.2006, 16:29    Titel: Antworten mit Zitat

Kann es sein, dass es nicht schneller geht, weil die HDD nicht schneller kann?
_________________
goto work, send your kids to school
follow fashion, act normal
walk on the pavement, watch T.V.
save for your old age, obey the law
Repeat after me: I am free
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 25.04.2006, 17:10    Titel: Antworten mit Zitat

setzt du denn jedes mal die Priorität auf highest? is nur so ne überlegung von mir: kann sein, dass progs wie win explorer auch die Priorität ganz hoch setzen, so dass dein Programm "abgestuft" werden kann...

Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
The Lord of Programming
Living Legend


Alter: 37
Anmeldedatum: 14.03.2003
Beiträge: 3122

Medaillen: Keine

BeitragVerfasst am: 26.04.2006, 13:44    Titel: Antworten mit Zitat

FH hat Folgendes geschrieben:
Kann es sein, dass es nicht schneller geht, weil die HDD nicht schneller kann?

Hmm...wäre möglich, aber gibt es denn keine Captureprogramme, die sowas reibungslos schaffen ohne das System zu sehr zu belasten(z.B. ohne alles in den Speicher zu schreiben)?

DirectXer hat Folgendes geschrieben:
setzt du denn jedes mal die Priorität auf highest? is nur so ne überlegung von mir: kann sein, dass progs wie win explorer auch die Priorität ganz hoch setzen, so dass dein Programm "abgestuft" werden kann...

Gruß DXer

Möglich, aber was ergäbe das für einen Sinn?
Ich glaube kaum, dass Microsoft ihrem Explorer eine höhere Priorität zuschreiben. Spiele laufen ja normalerweise auch nicht entscheidend langsamer nur weil der Explorer im Hintergrund offen ist, sondern beanspruchen meistens sogar (fast) 100% der CPU-Leistung...
Jedes Mal setze ich die Prio nur insofern hoch, als wenn die Aufnahme mehrmals gestartet wird. Aber die Unstimmigkeiten treten ja schon beim ersten Mal auf.
_________________
www.visualgamesentertainment.net
Current projects: RDTDC(1), JLI-Vor-Projekt, Tetris(-Tutorial), JLI-Format
(1) Realtime Developer Testing and Debugging Console


Anschlag, Anleitung zum Atombombenbau, Sprengkörper...
Hilf Schäuble! Damit er auch was findet...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung Alle Zeiten sind GMT
Seite 1 von 1

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.


Powered by phpBB © 2001, 2005 phpBB Group
Deutsche Übersetzung von phpBB.de

Impressum