2 Fragen



  • hi zusammen,

    1.Frage:
    ich habe ein kleines Game in C programmiert, in welchem man mit einem Männchen herumgehen / springen kann und mit verschiedenen NPCs sprechen kann. In diesem Game gibt es auch eine Anzeige, wo die Lebensenergie (in Form einer Zahl am oberen Fenster-Rand) angezeigt wird, für diese Anzeige musste ich einen eigenen Prozess starten. Wenn jetzt das Männchen läuft und gleichzeitig die Anzeige für die Lebensenergie ändert, dann wird die Zahl für die Lebensenergie hinter dem Männchen ausgegeben, anstatt am oberen Fenster-Rand. Kann mir jemand einen Tipp geben, wie ich das lösen könnte, dass das nicht mehr passiert?

    2.Frage:
    wie kann ich einem String einen Text mit Variablen übergeben? z.B.

    strcpy(string,"Test %i",%zahl); //geht eben nicht, aber wie könnte ich das lösen?

    gruss

    nightmare_frog



  • Zu Frage 1:

    Kann ich nicht sagen, weil ich nicht weiß, welche Blbliothek Du verwendest (stdio.h, conio.h?) und wie Du die Ausgaben der Prozesse (oder eher Threads???) synchronisierst.

    Zu Frage 2:

    sprintf(string, "Test %i", zahl);



  • erst mal danke für die schnelle Antwort. 🙂

    ich verwende conio.h (also eigentlich ja conio.c) und benütze die Funktion gotoxy(). Und was meinst du, mit " wie Du die Ausgaben der Prozesse (oder eher Threads???) synchronisierst. " ? Also so viel ich weiss muss ich meine Threads (ich dachte, das sei das gleiche wie ein Prozess...) nicht synchronisiere..

    gruss

    nightmare_frog



  • Hi,

    In der CONIO-Datei sind Fensterfunktionen und Funktionen zum setzen des Cursors (window() und gotoxy()) definiert, in STDIO nicht. Daher meine Frage danach.

    Befor Du etwas ausgibst (ob nun grafische Zeichen oder sonst einen Text), kannst Du ein solches Fenster setzen. Dann erfolgt die Ausgabe in diesem Bereich. Das jeweilige Fenster muss vor jeder Ausgabe gesetzt werden. Damit verhindert man, das andere Bereiche des Bildschirmes überschrieben werden.

    Wenn wenig Text ausgegeben wird (also nicht mehr als eine Zeile), dann reicht ein ein einfaches gotoxy().

    Wenn zwei Threads laufen, dann laufen sie asynchron. Es kann sein, das Thread 1 für eine Textausgabe gotoxy(1, 1) aufruft. In diesem Moment beginnt Thread 2 mit der Arbeit und ruft gotoxy(10, 5) auf. Nun arbeitet wieder Thread 1 und gibt seinen Text aus, allerdings steht der Cursor jetzt bei 10, 5... OK???

    "Synchronisieren" heißt also, dass die Threads aufeinander warten müssen. Dafür verwendet man sogenannte Semaphoren, die solche "kritischen Abschnitte" (Critical Sections) schützen.

    Näheres dazu findest Du in der Online-Hilfe unter "EnterCriticalSection" oder "LeaveCriticalSection".

    Diesen Effekt kannst Du auch über eine globale Variable erreichen, z.B. so:

    //
    // Thread 1:
    //
    void Ausgabe()
    {
        while( global_var != 0 )  // nichts tun, wenn Thread 2
            ;                     // gerade darauf zugreift.
    
        global_var = 1;           // für Thread 1 reservieren!
    
        gotoxy(1, 1);
        cputs("Text...");
    
        global_var = 0;          // wieder freigeben.
    }
    
    //
    // Thread 2:
    //
    void Ausgabe()
    {
        while( global_var != 0 )  // nichts tun, wenn Thread 1
            ;                     // gerade darauf zugreift.
    
        global_var = 1;           // für Thread 2 reservieren!
    
        gotoxy(10, 5);
        cputs("Anderer Text...");
    
        global_var = 0;          // wieder freigeben.
    }
    

    Der Nachteil davon ist, das das Programm dann mit der Performance in die Knie geht, weil die Threads oft nur in der Warteschleife hängen. Mit den Critical Sections löst das Betriebssystem das Problem, so dass kaum Einbußen in der Geschwindigkeit zu spüren sind.

    Gruß,
    Andreas



  • danke viel mal, das war genau das Problem das ich hatte. Ich versuche es jetzt zuerst mal so wie du es mir beschrieben hast, da mein Game sowieso nur aus ASCII-Zeichen besteht und das DOS-Fenster seeeeeehr langsam reagiert spielt die Performance nicht so eine grosse Rolle....

    gruss

    nightmare_frog



  • Original erstellt von ags:

    //
    // Thread 1:
    //
    void Ausgabe()
    {
        while( global_var != 0 )  // nichts tun, wenn Thread 2
            ;                     // gerade darauf zugreift.
    
        global_var = 1;           // für Thread 1 reservieren!
    
        gotoxy(1, 1);
        cputs("Text...");
    
        global_var = 0;          // wieder freigeben.
    }
    
    //
    // Thread 2:
    //
    void Ausgabe()
    {
        while( global_var != 0 )  // nichts tun, wenn Thread 1
            ;                     // gerade darauf zugreift.
    
        global_var = 1;           // für Thread 2 reservieren!
    
        gotoxy(10, 5);
        cputs("Anderer Text...");
    
        global_var = 0;          // wieder freigeben.
    }
    

    Und was passiert, wenn genau zwischen dem Ende der while Schleife und der Zeile "global_var=1" ein Taskwechsel stattfindet?



  • DrZoidberg:
    Und was passiert, wenn genau zwischen dem Ende der while Schleife und der Zeile "global_var=1" ein Taskwechsel stattfindet?

    Stimmt genau!

    Also Nightmare Frog: Sorry! Mir lag daran, dass Du das Prinzip verstehst. In der Eile vergaß ich den Hinweis, dass die globale Variable nicht mit "echtem" 32-Bit-Multithreading funktioniert, sondern nur, wenn Du Multithreading emulierst (über Ereignissteuerung z.B., wie unter Win 3.1x).

    Lag wohl daran, dass ich DOS nicht sofort mit Multithreading in Verbindung bringe 😃



  • also das Prinzip habe ich verstanden :), und auch das Problem von DrZoidberg habe ich kapiert (allerdings ist das bei mir noch nie aufgetreten...), aber was ist der Unterschied zwischen "echtem" Multithreading und emuliertem Multithreading? Also wenn ich das in der Schule richtig verstanden habe, ist Multithreading, dass mehrere Prozesse gleichzeitig vom Prozessor bearbeitet werden können (das ist aber glaub ich bei den heutigen Intel / Amd-Prozis nicht der Fall), also muss das Multi-Threading vom BS übernommen werden, hast du das gemeint?

    gruss

    nightmare_frog



  • Original erstellt von nightmare_frog:
    **...Multithreading, dass mehrere Prozesse gleichzeitig vom Prozessor bearbeitet werden können (das ist aber glaub ich bei den heutigen Intel / Amd-Prozis nicht der Fall),...
    **

    Multiprozessorsysteme, P4:Hyperthreading



  • Vielleicht gibt es hier ein Genie, das in der Lage ist, die Unterschiede zwischen "echtem" und "unechtem" Multithreading in zwei Sätzen zu erklären 😉 😃 Ich kann es nicht 😞

    "echtes": Das Betriebssystem steuert (entscheidet), welcher Prozess zu welchem zeitpunkt arbeitet (so macht es Win98, WinNT, Win2000 usw.).

    "emuliertes" (besser: kooperatives): Jedes einzelne Programm entscheidet selbst, wie lange es arbeitet. Andere Programme arbeiten nur, wenn das aktuelle Programm die Herrschaft über den Prozessor FREIWILLIG wieder abgibt (so arbeitet Window 3.1x). Das geschieht über eine zentrale Ereignissteuerung, die man auch in einem Programm einbauen kann, so dass auch mehrere Threads innerhalb eines Programmes emuliert werden können.

    Und noch etwas zu einer Deiner älteren Fragen: Prozesse und Threads sind nicht das gleiche. Ein Prozess (z.B. ein Programm) kann mehrere Threads enthalten, enthält aber immer mindestens einen (den Hauptthread). Man könnte sagen: Das Betriebssysten verwaltet (enthält) Prozesse. Prozesse enthalten (verwalten) Threads.

    Gruß,
    Andreas



  • @ags
    du unterscheidest preemptives und non-preemtives Multitasking. das sind einfach zwei mechanismen und arten wie Multitasking/-threading implementiert sein kann. entweder verdrängend (OS hat kontrolle) oder freiwillige abgabe an einen anderen thread (nicht verdrängend)...
    beides hat vor- und nachteile in bezug auf stabilität, implementationsaufwand, geschwindigkeit...
    beides ist aber genau so echt wie unecht... 😉

    als echt würde ich sehen, dass zwei threads wirklich parallel ablaufen und das geht hald mal nur, wenn du mehr als einen prozesssor im system hast
    unecht heißt, du programmierst das ganze genau so, aus deiner sicht ändert sich nichts, aber da du nur eine CPU hast, kann immer nur ein Befehl nach dem anderen ausgeführt werden. (stell dir einfach ein ASM-Listing vor) Um nun trotzdem eine art multithreading zu erreichen wir zwischen den einzelnen tasks /threads in extrem kurzen zeitabständen hin- und hergeschalten... (siehe Scheduling)

    -> imho... 😉


Anmelden zum Antworten