Nochmal zu Threads



  • Hallo
    Folgendes Beispielprogramm

    void thread(void *lpParameter);
    
    int main () 
    { 
    
    for(UINT nCount = 0; nCount < 1; nCount++)               
        {
            char myChar[500];
            strcpy (myChar,"Halloo");
    
            _beginthread(thread, 0,(void *)myChar);
            Sleep(100);
            strcpy (myChar,"Sack");
            _beginthread(thread, 0,(void *)myChar);
        }
    for (;;){}  // Endlosschleife damit Threads bis zu ende ausgeführt werden.
    return EXIT_SUCCESS;
    } 
    
    void thread(void *lpParameter)
    {
    
        char str[MAX_PATH] ="\0";
        strcpy(str,(char*)lpParameter); //Legt eine lokale Kopie an
        cout <<str<<endl;
    }
    

    Wenn ich oben das Sleep herausnehme..
    Steht in der Ausgabe zwei mal Sack.
    Sonst natürlich Hallo Sack
    Wie kann das sein wenn das 2 unterschiedlich Threads sind.

    Ich brauche dazu unbedingt ne Lösung...
    Die Variable myChar wird in meinem Programm dauerhaft verändert.
    Nicht nur 2 mal wie im Beispiel...

    Viel spass bei ausprobieren ... Mir raucht bereits der Kopf

    gruss Bronxx



  • --> WinAPI



  • und bei mir kommt
    Haloooo
    Sack
    als Ausgabe...



  • eigentlich haben Threads nichts mit Standard C++ zu tun, ich habe den alten Thread nur hier im Standard C++ Forum geduldet weil es um cast ging.
    Diesmal Verschiebe ich aber in WinAPI Forum.
    .



  • spekulativ:
    vielleicht liegts daran das der Thread erst nach dem strcpy "drankommt"... Wie du das anders machen musst weiss ich net



  • hm merke grade das dass unlogisch war was ich gesagt habe 😃



  • Das ist doch klar, das kann nicht gut gehen. 🙂
    Da fehlt die Synchronisation. Synchronisieren kann man aber nicht mit Sleep.

    Also, eine schrittweise Analyse:
    Am Anfang: In myChar steht "Halloo".

    _beginthread(thread, 0,(void *)myChar);
    

    Jetzt wurde Windows gesagt:
    Starte mir bitte einen neuen Thread. Der Start soll an der Adresse der Funktion thread sein. Windows hat den Thread also evtl. noch gar nicht gestartet, d.h. evtl. wurde noch keine einzige Zeile von thread() ausgeführt!

    Sleep(100);
    

    Jetzt hat Windows genug Zeit, den neuen Thread auszuführen. Daher gibt dieser nun "Halloo" aus. Wenn das Sleep fehlt, wurd der Thread (wahrscheinlich) immer noch nicht begonnen, oder höchstens ein ganz bisschen.

    strcpy (myChar,"Sack");
    

    Jetzt wird "Sack" in myChar reingeschrieben. Wenn das Sleep oben fehlt, hat der erste Thread die Variable myChar noch gar nicht in den eigenen Puffer kopiert, daher wird er nun ganz sicher "Sack" ausgeben.

    _beginthread(thread, 0,(void *)myChar);
    

    Jetzt sagst du Windows: Starte mit noch einen Thread.
    Dieser gibt auf jeden Fall "Sack" aus.

    Fazit:
    Du musst die Threads synchronisieren, wenn du kein völliges Chaos verursachen willst. 🙂
    Für deine Zwecke, schau dir mal CreateCriticalSection, EnterCriticalSection, LeaveCriticalSection und DeleteCriticalSection an.



  • Liegt vielleicht nen Beispiel rum was man hier posten könnte
    🙂



  • ICh hab nun mal die MSDN durchwühlt,
    bin jedoch nicht zum gewünschten Erfolg gekommen.

    Hat jemand von euch vielleicht eine Idee, wie ich die Threads synchronisieren kann, ohne die Verwendung eines Sleep(X);

    Das Programm sollte dann so ablaufen das es immer "Hallo Sack" ausgibt (siehe oben)..

    Danke schonmal

    Bronxx





  • Nach langem suchen und einigen Tassen Kaffee bin ich nun zu einer Lösung gekommen. Damit vielleicht einige nach mir auch was davon haben poste ich mal meine Lösung..

    void thread(void *lpParameter);
    HANDLE S1, S2;
    
    int main () 
    { 
     S1 = CreateSemaphore(NULL, 0, 1, "Sema1");
     S2 = CreateSemaphore(NULL, 0, 1, "Sema2"); 
     char myChar[MAX_PATH];
    
     ReleaseSemaphore(S1, 1, NULL);           //Setzt den Token S1 (Sema1)
     strcpy (myChar,"Halloo");
     _beginthread(thread, 0,(void *)myChar);
     WaitForSingleObject(S2, INFINITE);      // Warte auf Token S2 (Sema2)
    
     ReleaseSemaphore(S1, 1, NULL);     // Setzt Token S1
     strcpy (myChar,"Sack");
     _beginthread(thread, 0,(void *)myChar);
     WaitForSingleObject(S2, INFINITE); // Wartet auf S2    
    
     for (;;){}  // Endlosschleife damit Threads bis zu ende ausgeführt werden.
             // Hier könnte man noch auf den letzen Thread warten
             //und würde sich die Endlosschleife sparen
    
    CloseHandle(S1);
    CloseHandle(S2);
    return EXIT_SUCCESS;
    } 
    
    void thread(void *lpParameter)
    {
      WaitForSingleObject(S1, INFINITE);    //Wartet auf Token S1 
      char str[MAX_PATH] ="\0";
      strcpy(str,(char*)lpParameter); // lokale Kopie des übergebenen Wertes 
      ReleaseSemaphore(S2, 1, NULL);  // Setzt den Token S2 der oben erwartet wird  
      cout <<str<<endl;
    }
    

    Also diese Lösung klappt perfekt..
    Die Threads sind synchronisiert und die Variablen werden sauber übergeben.
    In meinem richtige Programm laufen dadurch 30 Threads parallel.. und alle mit unterschiedlichen Werten.. (werden in einer FOR-Schleife gestartet)

    vielleicht findet dieser Eintrag ein Weg in di FAQ und kann anderen helfen..

    gruß
    Bronxx



  • Ist das wirklich der Sinn von Semaphoren bzw. Threads?
    Du blockierst den Hauptthread, während die Unterthreads laufen... oder ist das in deinem richtigen Programm nicht so?
    Semaphoren sind doch IMHO dazu da, irgendwas zu zählen und z.B. nur 3 Threads gleichzeitig Zugriff auf irgendwelche Daten zu gewähren.



  • @Bronxx: Müßte nicht eine Semaphore ausreichen? Du mußt doch lediglich sicherstellen das nur ein Thread auf myChar zugreifen kann.

    @cd9000: Semaphoren sind da um kritische Abschnitte sicher zu umschiffen. Wie zum Beispiel: Ein Thread schreibt Daten in den Speicher während ein weiterer versucht von dieser Stelle Daten zu lesen. Also sollte der schreibende Thread diese Speicherstelle blockieren bis er mit seinem Schreibvorgang fertig ist. Ansonsten könnte es zu undefiniertem Verhalten führen. Wie man am Beispiel von Bronxx erkennen kann.



  • Kann mal einer bitte ein Bsp für CriticalSections posten, denn ich hab da Probleme damit. Wäre ihm sehr dankbar.



  • @Slowmotion:
    Nimmt man dafür nicht CriticalSection?

    Wie ich schon weiter oben geschrieben habe:
    Schau dir mal CreateCriticalSection, EnterCriticalSection, LeaveCriticalSection und DeleteCriticalSection an.

    Du musst die CS mit CreateCriticalSection initialisieren. Dann an mehrere Threads verteilen. Sobald ein Thread EnterCriticalSection aufruft, sind die anderen Threads blockiert, wenn sie auch versuchen EnterCriticalSection aufzurufen. Dadurch wird gesichert, dass immer nur ein Thread auf bestimmte daten zugreift.
    Mit LeaveCriticalSection teilt der Thread Windows mit, dass die anderen Threads auch wieder laufen dürfen.
    Am Ende des Progarmms löscht man mit DeleteCriticalSection die CS.

    Steht aber auch alles in der platform sdk doku.



  • Nun
    @cd9000

    Ich gebe in meinem richtigen Programm, direkt nach der Variablenübergabe den mainthread wieder frei. im eigentlichen Thread beginnt dann eine durchsuchfunktion und anschließend eine Kopierfunktion.
    Währenddessen startet die mainfunkrion schon wieder die nächste aktion, wobei myChar erneut verändert wird.

    Ich denke der Sinn ist erhalten geblieben.
    Nur oben im Beispielprogramm ist es etwas sinnlos, denn dort laufen die Threads ja nicht nebeneinander, sondern nacheinander...

    void thread(void *lpParameter)
    {
      WaitForSingleObject(S1, INFINITE);    //Wartet auf Token S1 
      char str[MAX_PATH] ="\0";
      strcpy(str,(char*)lpParameter); // lokale Kopie des übergebenen Wertes 
      ReleaseSemaphore(S2, 1, NULL);  // Setzt den Token S2 der oben erwartet wird  
      cout <<str<<endl;
    
    // Alles was ab hier gestartet wird läuft parallel zu dem Hauptthread, bzw zu 
       den nebenthreads
    
    }
    

    gruß Bronxx


Anmelden zum Antworten