Ich habe eine Frage bzgl Thread Programmierung. Ist mir zwar etwas peinlich dahingehend nachzufragen, da Thread Programmierung ja eigentlich von der Hand gehen "sollte", aber ich bin mir nicht sicher ob ich das richtig gemacht bzw richtig verstanden habe. Ich möchte eine Konsolenanwendung schreiben die ganz klassisch eine Haupt-Schleife enthält. Nun ist es ja gar kein Thema einfach ein while (flag == FALSE) { blubb (); flag = ...; } zu programmieren. Funktioniert auch sehr gut (also das blubb steht dann für die Schleifenanweisung). Nur habe ich bedingt durch die endlos while schleife eben auch immer eine sehr hohe Prozessor-Auslastung. Da ich in den Anweisungen Audio verarbeite und diese Brute-Force Methode eben nicht das gelbe vom Ei ist, habe ich Störungen (z.b. bei einem Fenster-Wechsel, oder wenn ich mit dem Firefox surfe). Nun möchte das Problem der hohen Auslastung (und der Störungen) durch Thread-Programmierung umgehen. Sprich, in meiner Thread-Funktion lasse ich dann die Hauptschleife laufen, und Erzeuge in der int main (...) den Thread. Meine Frage ist nun folgende : Ich muß ja im Hauptprogramm (also in der main) dafür sorgen das das Programm nicht automatisch wieder verlassen wird (also das nach dem CreateThread direkt durch ein return 0 mir mein eig. Hauptprogramm beendet wird). Nun wäre es ja vollkommener Blödsinn, das Hauptprogramm durch eine while (1) { } Schleife am leben zu halten und im Thread die eigentliche aufgabe abzuarbeiten (sonst hätte ich ja direkt bei der Hauptschleife ohne Thread bleiben können, außerdem löst es nicht das Problem der Prozessorauslastung). Mein zweiter Gedanke ist dann gewesen das ich ähnlich wie bei der Programmierung von Windows-Fenster-Applikationen in der Hauptschleife ein while (GetMessage (&msg, NULL, 0, 0)) { TranslateMsg (&msg); Dispatch (&msg); } zu machen, während der Thread im Hintergrund arbeitet. Also das das Hauptprogramm Nachrichten empfangen kann (selbst wenn ich in der Konsolenanwendung keine richtige Nachrichten-Queue habe) und durch diese Abarbeitung am Leben gehalten wird. Wenn ich eine reine Windows-Fenster-Applikation schreiben würde, wäre das ja auch richtig so (also Thread erstellen, Nachrichten Queue in Hauptschleife abarbeiten). Dadurch das ich aber eben eine Konsolenanwendung habe, und dadurch bedingt keine Nachrichten-Queue als solches (ich möchte insg. so wenig wie möglich Overhead haben um meine Applikation zu implementieren, und für diese Anwendung reicht eine Konsolenanwendung völlig aus) scheint mir das dennoch nicht der richtige Weg zu sein. Also nochmal im kurzumriss : Bisher : int main (...) { char flag = 0; vMainInit(); while (flag == 0) { if (kbhit ()) { if (getch () == 0x1b) { flag = 1; } else { ... } } } return 0; } Soll durch : DWORD WINAPI ulThread (void *pvData) { char flag = 0; vMainInit(); while (flag == 0) { if (kbhit ()) { if (getch () == 0x1b) { flag = 1; } else { ... } } } return 0; } int main (...) { MSG msg; CreateThread (NULL, 0, &ulThread, 0, 0, 0); // hier ist der Abschnitt bei dem ich nicht weiß ob die "Gestaltung" // richtig ist. while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } } ersetzt werden. (Die eig. Anweisung auf einen Tastendruck zu reagieren ist nur beispielhaft, da in meiner Anwendung eben Tastendrücke wie Timer-Funktionen [über GetTickCount)] und eben auch Audio läuft) Meine Frage (ums nochmal kurz zu machen) : Ist die Hauptschleife in der main-Funktion brauchbar um die Konsolenanwendung am leben zu halten ? Oder gibt es da bessere Lösungen ? Ich habe mich zwar schon in Thread-Programmierung eingelesen (ich habe ein Buch über Windows-Programmierung da, aber da wird eben explizit auf Fenster-basierte Programmierung eingegangen und nicht eben Konsolenapplikationen, daher auch die Idee mit der Nachrichten-Queue) Wie gesagt ursprünglich hab ich in der main Funktion den eigentlichen Hauptschleifen Code, aber durch das bedingte while (1) ist die Prozessorauslastung sehr hoch und es gibt Störungen (Pausen) bei der Abarbeitung des Programms. Ich möchte (um ein etwaiges : "Warum schreibst du nicht eine Windows-Fenster-Anwendung ?" vorzubeugen) eine reine Konsolenanwendung haben weil ich so wenig wie möglich Overhead haben will. Eine weitere Frage ist auch : Hätte ich wenn ich die Nachrichten-Queue in der Konsolenanwendung abarbeite die Möglichkeit auch per PostMessage Daten an diese Queue zu schicken, oder käme ich um ein RegisterWindow (wie es ja in der Windows-Programmierung erforderlich ist) nicht drum rum weil eine Konsolenanwendung per se keine Nachrichten-Queue hat ? Es ist ein bissl schwammig formuliert aber ich kann hier nicht den kompletten Code Posten, zumal es sich eig. nur um die Hauptschleife geht, und wie man ein sauberes Abarbeiten in der Konsolenanwendung realisieren würde. Hoffe diese Frage ist nich zu peinlich.
hm, ich habe es jetzt zweimal gelesen und weiß immer noch nicht recht, wie das Programm aussehen soll. Es soll also eine Konsolenanwendung sein, ok. Windows-Nachrichten soll es nicht verarbeiten. Dann braucht man auch keine-Message-Schleife. Die eigentliche Arbeit wird im Thread erledigt, das Hauptprogramm hat nichts sinnvolles zu tun. Dann kann man tatsächlich auch gleich den Code vom Thread ins Hauptprogramm zurück verlagern. Das kann es also auch nicht sein, sonst wärst du da schon selbst drauf gekommen. Soll der Thread irgendwas arbeiten, während in main() nur auf Tastatureingabeb gewartet wird, die dnan irgendwelche Flags setzen sollen? Dann könnte das so aussehen:
1 | int main() |
2 | {
|
3 | CreateThread (NULL, 0, &ulThread, 0, 0, 0); |
4 | while( "morgen ist auch noch ein Tag" ) |
5 | {
|
6 | switch( getch() ) |
7 | case 'a': |
8 | flaga = true; |
9 | break; |
10 | case 'b': |
11 | // ...
|
12 | break; |
13 | default:
|
14 | // oioioi!
|
15 | }
|
16 | }
|
Weil getch immer auf das nächste Zeichen wartet, verbrät main() dann kaum Rechenzeit. Will man nicht nur auf Tastendrücke warten, sondern auch noch auf etwas anderes (z.B. abgelaufene Zeit, Zeichen von serieller Schnittstelle etc.), darf getch() natürlich nicht blockieren. Dann könnte man etwa sowas bauen:
1 | int main() |
2 | {
|
3 | CreateThread (NULL, 0, &ulThread, 0, 0, 0); |
4 | while( "morgen ist auch noch ein Tag" ) |
5 | {
|
6 | // Ggf. auf Tastatur reagieren:
|
7 | if( kbhit() ) |
8 | {
|
9 | switch( getch() ) |
10 | case 'a': |
11 | flaga = true; |
12 | break; |
13 | case 'b': |
14 | // ...
|
15 | break; |
16 | default:
|
17 | // oioioi!
|
18 | }
|
19 | |
20 | // Ggf. auf etwas anderes reagieren
|
21 | if( anderesEreignis ) |
22 | {
|
23 | // ...
|
24 | }
|
25 | Sleep( 50 ); // kurzes Nickerchen schadet nicht |
26 | }
|
27 | }
|
Die Anzahl msec, die man bei jeden Durchlauf wartet, stellt man so ein, daß auf Ereignisse ausreichend schnell reagiert wird. Zu kleine Werte kosten dann mehr Rechenzeit. Die Anzahl der Ereignisse pro Zeit, die man durchsetzen kann, ist aber durch das Warten limitiert. Das kann man so verbessern:
1 | int main() |
2 | {
|
3 | CreateThread (NULL, 0, &ulThread, 0, 0, 0); |
4 | while( "morgen ist auch noch ein Tag" ) |
5 | {
|
6 | // Ggf. auf Tastatur reagieren:
|
7 | if( kbhit() || anderesEreignis ) |
8 | {
|
9 | if( kbhit() ) |
10 | {
|
11 | switch( getch() ) |
12 | case 'a': |
13 | flaga = true; |
14 | break; |
15 | case 'b': |
16 | // ...
|
17 | break; |
18 | default:
|
19 | // oioioi!
|
20 | }
|
21 | |
22 | // Ggf. auf etwas anderes reagieren
|
23 | if( anderesEreignis ) |
24 | {
|
25 | // ...
|
26 | }
|
27 | }
|
28 | else
|
29 | {
|
30 | Sleep( 50 ); // kurzes Nickerchen schadet nicht |
31 | }
|
32 | }
|
33 | }
|
Dann wird nur geschlafen, wenn wirklich nichts anliegt. Solange genug zu tun ist, wird kein Sleep() aufgerufen.
Programmierst du unter Linux? Dann schau dir mal die manpages von select und pthread an. Ich würde mit select schlafen, bis das terminal was empfängt und dann wacht select automatisch auf. also so: [c] meinthreadfunktion() { while(1) //mache das Audiozeug, schlafe so oft es geht!! } int main() { pthread_init(meinthreadfunktion); while(1) { int k=select(/* siehe manpage*/) if(k>0){ //Werte nutzereingabe aus } } }
nochmal der code:
1 | meinthreadfunktion() { |
2 | while(1) |
3 | //mache das Audiozeug, schlafe so oft es geht!!
|
4 | }
|
5 | |
6 | int main() { |
7 | pthread_init(meinthreadfunktion); |
8 | while(1) { |
9 | int k=select(/* siehe manpage*/) |
10 | if(k>0){ |
11 | //Werte nutzereingabe aus
|
12 | }
|
13 | }
|
14 | }
|
naja, wenn er es schon mit TranslateMessage() und DispatchMessage() probiert hat, wird es Windows sein. Da geht select() leider nur für Sockets, nicht für andere file-Deskriptoren.
hmm, da würde mir nur noch cygwin einfallen, aber ich bezweifle dass das gewollt ist :)
Moin, Um mal auf den Kern des Problems zurück zu kommen, du willst eine Audiodatei bauen und hast Probleme, Wenn du neben dem Programm noch andere Programme verwendest? Wenn das so richtig ist, bist du mit Threads komplett falsch beraten, denn: Windows setzt dein Programm selbst in einen Thread und gibt ihm anscheinend recht viel CPUzeit, wenn du jetzt ein 2. Programm auf hast, dann belegt dir das 1. Arbeitsspeicher und 2. braucht es Cpuzeit weil dieses ebenfalls in einen Thread gestartet wird. Das Ende vom Lied ist ein 2. Thread in deinem Programm bringt rein gar nichts, du musst deinen Algorithmus überarbeiten denn der beansprucht zu viel Resourcen, ich tippe mal auf lange zusammenhängende Speicherbereiche im Ram, die wahrscheinlich nicht komplett reserviert sind, und bei Start eines weiteren Programmes wenn dir der Arbeitsspeicher knapper wird überschrieben werden könnten. dh. vllt Pointerfehler oder Fehler in der Speicherresevierung. das sind nur Vermuttungen ich kenne dein ganzes Programm nicht!!
erstmal danke für die antworten. ich glaube mein problem liegt aber wohl woanders. wie schon richtig erkannt arbeite ich unter windows. mein problem ist wohl eher das ich im hauptprogramm nur mit polling arbeite und dadurch sehr viel zeit mit nichtstun verbrauche. daran würde auch ein thread nichts ändern. das polling lässt sich nicht umgehen, da ich den gesamten quellcode per compilerschalter für den avr compilierbar machen möchte, und auf dem zielsystem eben keine event-abarbeitung im sinne von windows mit den nachrichten-queues habe, müssten da größere teile des codes geändert werden was aber das umschalten beim compilieren erschwert. ich denke ich muß mit dem manko leben das ich enorm viel rechenzeit durch das polling verbrate. der thread kann da bestenfalls durch ein sleep (20); kurrzeitig schlafen gelegt werden, was vllt auch den rechenzeit-verbrauch etwas minimiert.
@Tecnologic >Um mal auf den Kern des Problems zurück zu kommen, du willst eine >Audiodatei bauen ... nicht ganz. um mal kurz mein ziel zu schildern : ich bin dabei eine simulation des audio-projektes zu programmieren. da der zielprozessor ein avr kann ich natürlich nicht wie unter windows programmieren (sprich malloc, OOP, threads und dergleichen). also schreibe ich das programm für den avr und mache eine portierung auf windows (inkl der pgm_read_xxx aufrufe). da der avr in einer endlosschleife läuft sollte das windows programm sich ähnlich verhalten, nur das unter windows eben in der hauptschleife noch die eig. simulationsaufgaben (simulation des DSPs mit audio-ausgabe, empfangen von tastatur-befehlen und umsetzung auf die avr-c-schnittstellen, kommunikation mit anderen programmen per mailslot und memory-mapped files um z.b. auch das auf dem zielsystem vorhandene touch-display zu simulieren, oder um direkt in die DSP-Simulation "reingucken" zu können [so soll es möglich sein eine art "tastkopf" auf ein bestimmtes audio-signal im dsp zu setzen, und in einem grafischen zusatzprogramm auf einem software-scope sichtbar zu machen], oder eben um in echt angeschlossene potis, schalter und knöpfe grafisch darstellen zu können und verwenden zu können) laufen. ich denke bei dieser konstellation (und vor allem den anspruch den quellcode [abgesehen von der simulierten hardware und den schnittstellen] fast 1:1 verwenden zu können) ist es nur schwer möglich ein "waschechtes" windows-programm (also nachrichten-basiert) daraus zu machen ohne das es bei der compilation auf dem zielsystem zu zu großen änderungen kommt.
Zu deinem eigentlichen Problem kann ich nichts sagen, aber mal eine andere Idee: wieso schreibst du nicht für DSP- und Steuerteil zwei getrennte Programme, die nur über ein Socket kommunizieren, und zwar im selben Befehlsformat das auch die Hardware verwendet? Wenn du dann statt dem Socket einen seriellen Port öffnest kannst du dann auch den echten DSP mit der PC-Software steuern, und den simulierten DSP mit der echten Steuerhardware. Erfordert evtl. etwas Rücksichtnahme auf das unterschiedliche Timing von Hardware und Simulation, aber wenn das robust läuft könnte es die Weiterentwicklung von beiden Teilen stark vereinfachen.
@andreas ich war auch schon mit einer solchen aufteilung am überlegen, hab mich aber dafür entschieden dsp-simulation und steuerteil entweder komplett im uC oder in der simulation laufen zu lassen. ich hab das aus dem grund gemacht da ich nachher eine übergeordnete pc-applikation haben möchte mit der ich die audio und steuermodule (im gesamtystem) untereinander verbinden kann. und diese pc-applikation würde dann wahlweise auf die simulation oder eben auf die reale hardware zugreifen. und wenn ich für die simulation dann noch 2 zusätzliche programme (ein dsp-simulationsteil und ein steuer-simulationsteil) benötige wär mir das zu umständlich, zumal der steuerteil sich 1:1 für win32 wie für den avr compilieren lässt und nur die eig. hardware simuliert werden muß und es somit nur wenig mehr aufwand ist.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.