CAS ? Threads zusammenarbeiten lassen.



  • HI !
    Ich über mich gerade in der Programmierung mit Threads.
    Mein Ziel ist es die Threads parallel arbeiten zu lassen.
    Mein Programmcode zur übersicht:

    #include <stdio.h>
    #include <clocale>
    #include <locale>
    #include <process.h>
    #include <windows.h>
    #include <conio.h>
    #include <iostream>
    //jetzt mit allen includes
    #define NUM_THREADS 2
    using namespace std;
    
    unsigned __stdcall RunThreadA(void *params);
    unsigned __stdcall RunThreadB(void *params);
    
    BOOL localeSet = FALSE;
    
        int f=0;
    int main()
    {	
    
        HANDLE threads[NUM_THREADS];
    
        unsigned aID;
        threads[0] = (HANDLE)_beginthreadex(
            NULL, 0, RunThreadA, NULL, 0, &aID);
    
        unsigned bID;
        threads[1] = (HANDLE)_beginthreadex(
            NULL, 0, RunThreadB, NULL, 0, &bID);
    
        WaitForMultipleObjects(2, threads, TRUE, INFINITE);
    
        CloseHandle(threads[0]);
        CloseHandle(threads[1]);
    
        system("pause");
        return 0;
    }
    
    unsigned __stdcall RunThreadA(void *params)
    {
        do  {
    	f++;
    	cout << ",";
    	}
        while(f !=100);
    
        return 1;
    }
    
    unsigned __stdcall RunThreadB(void *params)
    {
        do  {
    	f++;
    	cout << ".";
    	}
        while(f !=100);
    	localeSet = TRUE;
    
        return 1;
    }
    

    Mein Ziel ist es 100 Zeichen in der Reihenfolge ,.,.,.,.,.,.,.,., usw. in der ausgabe zu haben aber das Programm gibt mir ledigtlich ...,,...,,,,,,,... usw. aus.
    Ich habe es schon mit Mutex versucht aber dort war das ergebnis ähnlich.
    Jetzt wurde mit gesagt es sollte mit "CAS" klappen aber aus dem was mir die VS03 Hilfe gibt werde ich net wirklich schlau...

    Wie schaffe ich es das die Threads Paralel arbeiten ohne sich zu überschreiben ?

    Gruß
    Kaitos



  • Kaitos schrieb:

    Ich über mich gerade in der Programmierung mit Threads.
    Mein Ziel ist es die Threads parallel arbeiten zu lassen...

    ...Wie schaffe ich es das die Threads Paralel arbeiten ohne sich zu überschreiben ?

    1. Ich will dir nicht zu nahe drehten, aber wiedersprichst du dir jetzt nicht? Sollen die Threads nun parallel oder sequenziell ablaufen, wenn du letzteres willst, nimmt man eigentlich keine Threads dafür.

    2. Es wäre schön wenn du einen lauffähigen Code anzeigst, ist ja schön, das die Includes in der stdafx.h liegen, im Forum wäre es aber besser wenn du diese direkt reinschreibst. Auch weil du vermutlich das falsche Forum gewählt hast: Du verwendest die WinAPI-Threads, oder? (Wenn du statt dessen die Boost-Threads verwenden würdest, die wohl auch denen aus dem nächsten C++ Standard ähneln, wärst du hier wohl richtig).

    3. Wenn beide Threads auf eine gemeinsame Ressource (hier z.B. "int f") zugreifen, so ist diese zu schützen (Thema Mutex/Critical Section...). Es sei den du Führst wirklich "atomare" Operationen durch (f++ ist das mit Sicherheit nicht, und selbst ++f würde ich hier nicht vertrauen).

    cu André



  • unter windoose gibts, um von mehreren threads auf eine gemeinsame variable zuzugreifen, die 'InterlockedXXX'-funktionen.
    beispiel:

    unsigned __stdcall RunThreadA(void *params)
    {
        unsigned local_copy;
        do  
        {
          local_copy = InterlockedIncrement (&f);  // hochzählen
          putchar (',');
        }
        while(local_copy < 100);
    
        return 1;
    }
    

    🙂



  • Kaitos schrieb:

    ...

    Mein Ziel ist es 100 Zeichen in der Reihenfolge ,.,.,.,.,.,.,.,., usw. in der ausgabe zu haben aber das Programm gibt mir ledigtlich ...,,...,,,,,,,... usw. aus.

    ...

    Gruß
    Kaitos

    Wie asc schon geschrieben hat solltest du bei sequenziellen Abläufen keine Threads verwenden...

    Ansonsten brauchst du für deine Übung zwei Mutexe die gegenseitig notifiziert werden.

    Main_Func
    Create two threads
    Create two mutex
    
    Init Mutex for thread 1
    
    Wait for threads
    
    Thread 1
    while f < 100
    Wait for mutex thread 1
    output ','
    set mutex thread 2
    end while
    
    Thread 2
    while f < 100
    Wait for mutex thread 2
    output '.'
    set mutex thread 1
    end while
    

    Google Stichwörter:
    gegenseitiger Ausschluß
    Dekker Algorithmus
    Peterson Algorithmus



  • asc schrieb:

    Es sei den du Führst wirklich "atomare" Operationen durch (f++ ist das mit Sicherheit nicht, und selbst ++f würde ich hier nicht vertrauen).

    entweder du traust beiden, oder keinem davon. egal, wo sich das ++ befindet.
    🙂



  • Danke erstmal !

    @asc
    Ich will eine parallele Berechnung aber eine sequenzielle Ausgabe 🙄
    Naja es kommen nacher noch ein paar berechnungen dazu aber ich möcht das das Grundgerüst läuft.

    includes habe ich jetzt im Code.

    Die Variable 'f' ist nacher meine Globale variable und der rest bleibt intern in den Threads...

    @+fricky
    Hört sich interessand an brauche ich irgendwelche zusätzlichen includes dafür ?

    @Tobias Gerg
    Danke ich schaue es mir an und sage bescheidwenn ich daran verzweifle / es klappt 😉

    Danke der Peterson Algorithmus passt super in das was ich mir vorgestellt habe.
    (Aber wieso bin ich da nicht selbst drauf gekommen ? Schaut doch so einfach aus 😉 )



  • Kaitos schrieb:

    @+fricky
    Hört sich interessand an brauche ich irgendwelche zusätzlichen includes dafür ?

    nix spezielles, #include <windows.h>, und gut.

    Tobias: wieso 2 mutexe? unter win reicht einer (locken mit WaitForSingleObject und freigeben mit ReleaseMutex), bzw. noch besser: eine 'critical section', da mutexe eigentlich für prozessübergreifende synchronisation da sind (aber es funzt natürlich auch innerhalb eines prozesses).
    🙂



  • +fricky schrieb:

    ...
    Tobias: wieso 2 mutexe? unter win reicht einer (locken mit WaitForSingleObject und freigeben mit ReleaseMutex), bzw. noch besser: eine 'critical section', da mutexe eigentlich für prozessübergreifende synchronisation da sind (aber es funzt natürlich auch innerhalb eines prozesses).
    🙂

    Wenn du wechselseitigen Ausschluß willst kannst du dass mit einem Mutex machen? Da steh ich auf dem Schlauch...

    Wie stell ich mit einer Mutex sicher, dass der Switch zum zweiten Task erfolgt? Wird beim ReleaseMutex ?immer? ein Kontextwechsel ausgeführt?

    Wenn ja ist es mir klar... Wenn nicht, kannst du bitte ein Beispiel geben?

    Gruß
    Tobi



  • +fricky schrieb:

    ...
    Tobias: wieso 2 mutexe? unter win reicht einer (locken mit WaitForSingleObject und freigeben mit ReleaseMutex), bzw. noch besser: eine 'critical section', da mutexe eigentlich für prozessübergreifende synchronisation da sind (aber es funzt natürlich auch innerhalb eines prozesses).
    🙂

    Wenn du wechselseitigen Ausschluß willst kannst du dass mit einem Mutex machen? Da steh ich auf dem Schlauch...

    Wie stell ich mit einer Mutex sicher, dass der Switch zum zweiten Task erfolgt? Wird beim ReleaseMutex ?immer? ein Kontextwechsel ausgeführt?

    Wenn ja ist es mir klar... Wenn nicht, kannst du bitte ein Beispiel geben?

    Gruß
    Tobi



  • unsigned __stdcall RunThreadA(void *params)
    {
    	do	
    	{
    	if(p == 0)				
    		{
    		f=f-1;
    		cout << ",";
    		p=1;
    		Sleep(1);
    		}
    	}
    	while(f !=0);
    return 1;
    }
    
    unsigned __stdcall RunThreadB(void *params)
    {
    	do	
    	{		
    	if(p == 1)
    		{
    		f=f-1;
    		cout << ".";
    		p=0;
    		Sleep(1);
    		}
    	}
    	while(f !=0);
    localeSet = TRUE;
    return 1;
    }
    

    😃 Klappt aber wieso er das Sleep(1); habe will weis ich nicht ich weiß nur das es ohne das eine Endlosschleife hat.



  • Tobias Gerg schrieb:

    Wie stell ich mit einer Mutex sicher, dass der Switch zum zweiten Task erfolgt? Wird beim ReleaseMutex ?immer? ein Kontextwechsel ausgeführt?

    ja, wenn der andere task auf die freigabe des mutex wartet (wenn er z.b. in dem WaitForSingleObject-aufruf festhängt). hier: http://msdn.microsoft.com/en-us/library/ms686927.aspx
    🙂



  • Ganz allgemein: wenn es nicht mit Mutexen klappt, dann klappt es auch nicht mit anderen Synchronisationsmethoden. Die Berechnung soll parallel sein und die ausgabe sequentiell? Dann behandle Berechnung und Ausgabe getrennt. Ansonsten hast du zwar 2 Threads, die aber ein Problem sequentiell loesen, da sie sich gegenseitig blockieren.

    da mutexe eigentlich für prozessübergreifende synchronisation da sind

    Aeh nein, auch wenn unter Windows vielleicht andere Methoden der Synchronisation zuerst empfohlen werden. Beispiel Posix threads. Ausserdem steht in deinem Link nicht drin, wie garantiert wird, dass die Threads immer abwechselnd Zugriff auf die gemeinsame Ressource bekommen, sondern nur dass jeweils einer Zugriff drauf hat.



  • +fricky schrieb:

    ...
    ja, wenn der andere task auf die freigabe des mutex wartet (wenn er z.b. in dem WaitForSingleObject-aufruf festhängt). hier: http://msdn.microsoft.com/en-us/library/ms686927.aspx
    🙂

    Alles klar, dann genügt natürlich ein Mutex...

    Danke für den Link. 👍

    Gruß
    Tobi



  • knivil schrieb:

    da mutexe eigentlich für prozessübergreifende synchronisation da sind

    Aeh nein, auch wenn unter Windows vielleicht andere Methoden der Synchronisation zuerst empfohlen werden.

    ich meinte ja auch die windows-mutexe. dass der OP windows benutzt, wissen wir doch längst.

    knivil schrieb:

    Beispiel Posix threads.

    posix? wie jetzt? wofür?

    knivil schrieb:

    Ausserdem steht in deinem Link nicht drin, wie garantiert wird, dass die Threads immer abwechselnd Zugriff auf die gemeinsame Ressource bekommen, sondern nur dass jeweils einer Zugriff drauf hat.

    richtig. abwechselnd wird es nur, wenn jeder der beiden threads rechtzeitig in den lock rauscht, während der andere drin ist. aber dass so'n synchroner wechsel doof ist, hast du ja auch schon bemerkt.
    btw, damit beide threads frei rennen und sich trotzdem unterhalten können, bietet sich eventuell ein 'lock-free' FIFO an: http://kobodeluxe.sourcearchive.com/documentation/0.5.1/sfifo_8c-source.html



  • richtig. abwechselnd wird es nur, wenn jeder der beiden threads rechtzeitig in den lock rauscht, während der andere drin ist. aber dass so'n synchroner wechsel doof ist, hast du ja auch schon bemerkt.

    Aber so wie der OP es beschrieben hat, sollte es doch abwechselnd sein ,.,.,.,. . Ausserdem ist abwechseln nicht zwingend doof, da dann Threads nicht verhungern koennen. Posix threads war ein Beispiel fuer eine Threadbibliothek, die Mutexe anbietet aber nicht per se fuer Interprozesskommunikation. Und bevor jemand mit look-free Datenstrukturen oder Algorithmen hantiert, sollte er erstmal ein Gefuehl fuer normale Synchronisationsmechanismen entwickeln. Selbst die, die sich damit wirklich auskennen, machen dabei Fehler (link grad net parat).



  • knivil schrieb:

    Ausserdem ist abwechseln nicht zwingend doof, da dann Threads nicht verhungern koennen.

    Doch, denn dann sind Threads nämlich die falsche Lösung.
    Ein Thread verhungert wenn er nicht dran kommt - nicht wenn er nicht dauernd dran ist.



  • Mit abwechselnd meine ich, abwechselnd Zugriff auf eine Variable, aber die Berechnungen schon parallel.



  • knivil schrieb:

    Mit abwechselnd meine ich, abwechselnd Zugriff auf eine Variable, aber die Berechnungen schon parallel.

    Warum willst du parallele Berechnungen, wenn diese an einem Nadelöhr warten sollen? Dadurch wird deine parallele Berechnung effektiv wieder zu einer sequenziellen. Vermutlich wäre nach deiner Beschreibung dein "paralleles" Programm selbst auf einer Mehrprozessormaschine kaum schneller als ein sequenzielles Programm (vielleicht sogar langsamer).



  • Warum willst du parallele Berechnungen, wenn diese an einem Nadelöhr warten sollen?

    Warum sollte es ein Nadeloehr sein? Wenn das Holen/Schreiben des Wertes kurze Zeit beansprucht und die Berechnung lange dauert? (jedesmal etwa gleich lang)

    Dadurch wird deine parallele Berechnung effektiv wieder zu einer sequenziellen.

    Nein, da keine Datenabhaengigkeit zwischen den Threads bestehen muss.

    Vermutlich wäre nach deiner Beschreibung dein "paralleles" Programm selbst auf einer Mehrprozessormaschine kaum schneller als ein sequenzielles Programm (vielleicht sogar langsamer).

    Unbegruendete Behauptung. Und warum sollte es auf Mehrkernsystemen langsamer sein als auf Einkernsystemen (gleiche Taktzahl etc vorausgesetzt)? Wieviel Erfahrung hast du mit Multi thread programming? Selbst Anwendungen auf Einkernsysteme koennen von mehreren Threads profitieren (anwendungsspezifisch).



  • knivil schrieb:

    Unbegruendete Behauptung. Wieviel Erfahrung hast du mit Multi thread programming? Selbst Anwendungen auf Einkernsysteme koennen von mehreren Threads profitieren (anwendungsspezifisch).

    Nicht wenn du wie du es vorschlägst künstliche sperren einbaust.

    Das Problem bei diesem abwechslenden zugriff sind die standzeiten der threads. du hast standzeiten, egal wie du es implementierst. und das ist der design fehler.

    lass die threads parallel laufen und synchronisieren den zugriff auf die zentrale variable korrekt und du hast ein viel besseres system. nur eben dass das ergebnis halt nicht ABABABABABA sondern AAABBAAABBBBBBBAABBAAAA ist...

    wenn es wichtig ist dass ABABA raus kommt, dann macht man es über einen 3. thread der von der einen seite lauter A und von der anderen Seite lauter B bekommt und diese dann verschmilzt - nach dem gewünschten muster.

    uU muss es auch kein thread sein sondern die datenstruktur kann das uU auch selber... jedenfalls ist ein erzwingen eines nacheinander ablaufens eines parallelen programms keine gute idee.


Log in to reply