2010-09-03 38 views
5

Ich habe ein Problem mit der Reihenfolge der Ausführung der Threads nacheinander erstellt. Hier ist der Code.Boost :: Threads Ausführung Reihenfolge

#include <iostream> 
#include <Windows.h> 
#include <boost/thread.hpp> 

using namespace std; 

boost::mutex mutexA; 
boost::mutex mutexB; 
boost::mutex mutexC; 
boost::mutex mutexD; 


void SomeWork(char letter, int index) 
{ 
    boost::mutex::scoped_lock lock; 
    switch(letter) 
    { 
    case 'A' : lock = boost::mutex::scoped_lock(mutexA); break; 
    case 'B' : lock = boost::mutex::scoped_lock(mutexB); break; 
    case 'C' : lock = boost::mutex::scoped_lock(mutexC); break; 
    case 'D' : lock = boost::mutex::scoped_lock(mutexD); break; 
    } 

    cout << letter <<index << " started" << endl; 
    Sleep(800); 
    cout << letter<<index << " finished" << endl; 
} 

int main(int argc , char * argv[]) 
{ 
    for(int i = 0; i < 16; i++) 
    { 
     char x = rand() % 4 + 65; 
     boost::thread tha = boost::thread(SomeWork,x,i); 
     Sleep(10); 
    } 
Sleep(6000); 
    system("PAUSE"); 
    return 0; 
} 

jedes Mal, wenn ein Brief (von A bis D) und eine genereaion ID (i) das Verfahren SomeWork als Thread weitergeleitet wird. Die Reihenfolge der Ausführung zwischen den Buchstaben ist mir egal, aber für einen bestimmten Buchstaben, sagen wir A, muss Ax vor Ay beginnen, wenn x < y. ein zufälliges Teil einer zufälligen Ausgabe des Codes ist:

 
B0 started 
D1 started 
C2 started 
A3 started 
B0 finished 
B12 started 
D1 finished 
D15 started 
C2 finished 
C6 started 
A3 finished 
A9 started 
B12 finished 
B11 started --> B11 started after B12 finished. 
D15 finished 
D13 started 
C6 finished 
C7 started 
A9 finished 

wie solche Bedingungen vermeiden können?
danke.


Ich löste das Problem mit Zustandsvariablen. aber ich habe das Problem ein wenig geändert. Die Lösung besteht darin, den Index der for-Schleife zu verfolgen. so weiß jeder Thread, wenn es nicht funktioniert. Aber was diesen Code betrifft, gibt es zwei andere Dinge, über die ich gerne nachfragen würde.
zuerst, auf meinem Computer, wenn ich den For-Schleife-Index auf 350 gesetzt hatte ich eine Zugriffsverletzung. 310 war die Anzahl der Schleifen, was in Ordnung war. Also habe ich festgestellt, dass es eine maximale Anzahl von Threads gibt, die generiert werden können. Wie kann ich diese Nummer bestimmen? Sekunde, in Visual Studio 2008 zeigte die Release-Version des Codes ein wirklich seltsames Verhalten. Ohne Verwendung von Bedingungsvariablen (Zeilen 1 bis 3 wurden auskommentiert) wurden die Threads geordnet. Wie konnte das passieren?

hier ist der Code:

#include <iostream> 
#include <Windows.h> 
#include <boost/thread.hpp> 

using namespace std; 

boost::mutex mutexA; 
boost::mutex mutexB; 
boost::mutex mutexC; 
boost::mutex mutexD; 


class cl 
{ 
public: 
    boost::condition_variable con; 
    boost::mutex mutex_cl; 
    char Letter; 
    int num; 
    cl(char letter) : Letter(letter) , num(0) 
    { 

    } 
    void doWork(int index, int tracknum) 
    { 
     boost::unique_lock<boost::mutex> lock(mutex_cl); 
     while(num != tracknum)  // line 1 
      con.wait(lock); // line 2 
     Sleep(10); 
     num = index; 
     cout << Letter<<index << endl; 
     con.notify_all(); // line 3 
    } 
}; 

int main(int argc , char * argv[]) 
{ 
    cl A('A'); 
    cl B('B'); 
    cl C('C'); 
    cl D('D'); 

    for(int i = 0; i < 100; i++) 
    { 
     boost::thread(&cl::doWork,&A,i+1,i); 
     boost::thread(&cl::doWork,&B,i+1,i); 
     boost::thread(&cl::doWork,&C,i+1,i); 
     boost::thread(&cl::doWork,&D,i+1,i); 
    } 
    cout << "************************************************************************" << endl; 

    Sleep(6000); 
    system("PAUSE"); 
    return 0; 
} 

Antwort

6

Wenn Sie zwei für die Sperre warten verschiedene Threads haben, ist es völlig nicht-deterministisch, welches es zu erwerben, sobald die Sperre durch den bisherigen Halter freigegeben wird. Ich glaube, das ist es, was du erlebst. Angenommen, B10 hält die Sperre, und in der Zwischenzeit werden Threads für B11 und B12 erzeugt. B10 gibt das Schloss frei - es kommt auf einen Münzwurf an, ob B11 oder B12 es als nächstes erwirbt, egal welcher Thread zuerst erstellt wurde, oder gar welcher Thread zuerst zu warten begann.

Vielleicht sollten Sie Arbeitswarteschlangen für jeden Buchstaben implementieren, so dass Sie genau 4 Threads spawnen, von denen jeder Arbeitseinheiten verbraucht? Nur so kann die Bestellung auf einfache Weise garantiert werden. Ein einfacher Mutex wird die Reihenfolge nicht garantieren, wenn mehrere Threads auf die Sperre warten.

+0

Was meinen Sie mit Arbeitseinheiten? –

+0

Einige Darstellungen einer Arbeit, die von einem Thread erledigt werden soll. In diesem Fall wäre eine Arbeitseinheit grundsätzlich ein '(Buchstabe, Index)' Paar. – Gian

2

Obwohl B11 vor B12 gestartet wird, ist nicht garantiert, dass eine CPU-Zeitscheibe für die Ausführung von SomeWork() vor B12 gegeben ist. Diese Entscheidung hängt vom Betriebssystem und seinem Scheduler ab.

Mutexs werden normalerweise verwendet, um den Zugriff auf Daten zwischen Threads zu synchronisieren, und es wurde ein Problem mit der Sequenz der Threadausführung (d. H. Datenzugriff) aufgeworfen.

Wenn die Threads für Gruppe 'A' denselben Code für die gleichen Daten ausführen, verwenden Sie nur einen Thread. Dadurch wird die Kontextumschaltung zwischen Threads in der Gruppe verhindert und das gleiche Ergebnis erzielt. Wenn sich die Daten ändern, berücksichtigen Sie ein Erzeuger/Verbraucher-Muster. Paul Bridger gibt ein leicht zu verstehendes Beispiel für Hersteller/Verbraucher here.

1

Ihre Threads haben Abhängigkeiten, die erfüllt sein müssen, bevor sie ausgeführt werden. In Ihrem Beispiel hängt B12 von B0 und B11 ab. Irgendwie musst du dieses Abhängigkeits-Wissen aufspüren. Threads mit nicht abgeschlossenen Abhängigkeiten müssen warten.

Ich würde in condition variables suchen. Jedes Mal, wenn ein Thread SomeWork() beendet, wird die Methode notify_all() der Bedingungsvariable verwendet. Dann müssen alle wartenden Threads prüfen, ob sie noch Abhängigkeiten haben. Wenn ja, geh zurück und warte. Andernfalls rufen Sie SomeWork() auf.

Sie müssen einen Weg für jeden Thread, um festzustellen, ob es nicht abgeschlossen Abhängigkeiten hat. Dies wird wahrscheinlich eine global verfügbare Einheit sein. Sie sollten es nur ändern, wenn Sie den Mutex (in SomeWork()) haben. Das Lesen mit mehreren Threads sollte für einfache Datenstrukturen sicher sein.

Verwandte Themen