|
JLI Spieleprogrammierung
|
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
|
Verfasst am: 23.04.2006, 12:52 Titel: WINAPI+Multithreading |
|
|
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 ):
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 |
|
|
Dragon Super JLI'ler
Alter: 38 Anmeldedatum: 24.05.2004 Beiträge: 340 Wohnort: Sachsen Medaillen: Keine
|
Verfasst am: 23.04.2006, 13:58 Titel: |
|
|
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 |
|
|
FH Super JLI'ler
Alter: 36 Anmeldedatum: 16.10.2004 Beiträge: 438
Medaillen: Keine
|
Verfasst am: 23.04.2006, 15:00 Titel: |
|
|
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 |
|
|
The Lord of Programming Living Legend
Alter: 37 Anmeldedatum: 14.03.2003 Beiträge: 3122
Medaillen: Keine
|
Verfasst am: 23.04.2006, 21:48 Titel: |
|
|
Danke
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
Oder wäre es unter diesen Umständen evtl. nötig, dass ich das Capture-Fenster auch in dem separaten Thread erstelle? _________________ 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 |
|
|
The Lord of Programming Living Legend
Alter: 37 Anmeldedatum: 14.03.2003 Beiträge: 3122
Medaillen: Keine
|
Verfasst am: 24.04.2006, 18:21 Titel: |
|
|
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 |
|
|
FH Super JLI'ler
Alter: 36 Anmeldedatum: 16.10.2004 Beiträge: 438
Medaillen: Keine
|
Verfasst am: 24.04.2006, 20:18 Titel: |
|
|
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 |
|
|
The Lord of Programming Living Legend
Alter: 37 Anmeldedatum: 14.03.2003 Beiträge: 3122
Medaillen: Keine
|
Verfasst am: 24.04.2006, 20:52 Titel: |
|
|
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 |
|
|
FH Super JLI'ler
Alter: 36 Anmeldedatum: 16.10.2004 Beiträge: 438
Medaillen: Keine
|
Verfasst am: 25.04.2006, 08:20 Titel: |
|
|
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 |
|
|
Dragon Super JLI'ler
Alter: 38 Anmeldedatum: 24.05.2004 Beiträge: 340 Wohnort: Sachsen Medaillen: Keine
|
Verfasst am: 25.04.2006, 13:08 Titel: |
|
|
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 |
|
|
The Lord of Programming Living Legend
Alter: 37 Anmeldedatum: 14.03.2003 Beiträge: 3122
Medaillen: Keine
|
Verfasst am: 25.04.2006, 14:40 Titel: |
|
|
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 |
|
|
FH Super JLI'ler
Alter: 36 Anmeldedatum: 16.10.2004 Beiträge: 438
Medaillen: Keine
|
Verfasst am: 25.04.2006, 16:29 Titel: |
|
|
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 |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 25.04.2006, 17:10 Titel: |
|
|
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 |
|
|
The Lord of Programming Living Legend
Alter: 37 Anmeldedatum: 14.03.2003 Beiträge: 3122
Medaillen: Keine
|
Verfasst am: 26.04.2006, 13:44 Titel: |
|
|
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 |
|
|
|
|
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
|