2012-04-16 4 views
6

Ich schrieb ein Programm schrieb und es funktioniert nicht so, wie ich es erwarte. Ich habe zwei Themen: thread löst func und anotherThread auslöst anotherFunc. Was ich tun wollte, ist, wenn cont Wert erreicht 10 in func, anotherThread ausgelöst werden mit pthread_cond_wait und pthread_cond_signal. Das seltsame Ding ist alles funktioniert gut, wenn ich die sleep(1) Linie auskommentiere. Ich bin neu in Threads und ich folgte dem Tutorial here und wenn ich die sleep Zeile in ihrem Beispiel kommentieren, bricht es auch.POSIX C-Gewinde. pthread_cond_t Beispiel. Funktioniert nicht wie erwartet

Meine Frage ist, wie kann ich das ohne sleep() Anrufe tätigen? Und was passiert, wenn in meinem Code sowohl funcpthread_mutex_lock nach anotherFunc erreicht? Wie kann ich diese Dinge kontrollieren? Dies ist mein Code:

#include <iostream> 
#include <stdlib.h> 
#include <stdio.h> 
#include <pthread.h> 

pthread_mutex_t myMutex; 
pthread_cond_t cond; 
pthread_attr_t attr; 

int cont; 

void *func(void*) 
{ 
    printf("func\n"); 

    for(int i = 0; i < 20; i++) 
    { 
     pthread_mutex_lock(&myMutex); 

     cont++; 
     printf("%d\n", cont); 
     if(cont == 10) 
     { 
      printf("signal:\n"); 
      pthread_cond_signal(&cond); 
//   sleep(1); 
     } 
     pthread_mutex_unlock(&myMutex); 
    } 
    printf("Done func\n"); 

    pthread_exit(NULL); 
} 

void *anotherFunc(void*) 
{ 
    printf("anotherFunc\n"); 
    pthread_mutex_lock(&myMutex); 
    printf("waiting...\n"); 

    pthread_cond_wait(&cond, &myMutex); 
    cont += 10; 
    printf("slot\n"); 

    pthread_mutex_unlock(&myMutex); 
    printf("mutex unlocked anotherFunc\n"); 
    printf("Done anotherFunc\n"); 

    pthread_exit(NULL); 
} 

int main(int argc, char *argv[]) 
{ 
    pthread_t thread; 
    pthread_t anotherThread; 

    pthread_attr_init(&attr); 
    pthread_mutex_init(&myMutex, NULL); 
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 
    pthread_cond_init(&cond, NULL); 

    pthread_create(&anotherThread, &attr, anotherFunc, NULL); 
    pthread_create(&thread, &attr, func, NULL); 

    pthread_join(thread, NULL); 
    pthread_join(anotherThread, NULL); 

    printf("Done MAIN()"); 

    pthread_mutex_destroy(&myMutex); 
    pthread_cond_destroy(&cond); 
    pthread_attr_destroy(&attr); 


    pthread_exit(NULL); 
    return 0; 
} 

Sorry für den langen Post, aber ich bin neu in Threads und ich bin bereit zu lernen. Kennen Sie auch einige gute Referenzen oder Kurse/Tutorials zu Themen und Netzwerken unter Linux? Ich möchte lernen, einen Chat-Client zu erstellen, und ich habe gehört, dass ich dafür Threads und Networking kennen muss. Problem ist, ich weiß nicht, ziemlich gut, wenn das, was ich lerne, in Ordnung ist, da ich nicht weiß, was ich wissen muss.

Vielen Dank :)

+0

Andere Bemerkungen. Zusätzlich zu "pthread_attr_t" müssen Sie statische Initialisierer für die Bedingung und Mutex verwenden, um den Code zu vereinfachen. Darüber hinaus können Ihre Thread-Funktionen einfach "NULL zurückgeben" oder "return 0;" anstelle von "pthread_exit" aufrufen. Und Ihr Hauptthread kann einfach "0;" aus main zurückgeben, ohne 'pthread_exit' aufzurufen. Die anderen Threads werden an diesem Punkt nicht ausgeführt, seit sie verbunden wurden. Rückgabe von Haupttruppen ein Prozess-Exit, aber 'pthread_exit' im primären Thread erzwingt keinen Prozess-Exit, was nützlich ist, um andere Threads laufen zu lassen. – Kaz

+0

Außerdem müssen statische Mutexe und Bedingungen nicht bereinigt werden. Verwenden Sie einfach 'pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;'. Die komplexen Initialisierungen werden für Situationen benötigt, in denen Sie ungewöhnliche Attribute festlegen möchten. Z.B. Mache einen robusten Mutex mit geteiltem Prozess. – Kaz

Antwort

9

Ihre anotherThread ruft einfach pthread_cond_wait ohne vorher testen, ob der gewünschte Zustand (gegen zehn erreicht) bereits geschehen ist. Das ist falsche Logik, die zu dem verlorenen Wakeup-Problem führt: der Name eines wiederkehrenden Fehlers, der falsch geschriebene Multithread-Programme plagt.

Zustandsvariablen sind zustandslos. Wenn pthread_cond_signal oder pthread_cond_broadcast unter einer Bedingung aufgerufen wird, auf der aktuell keine Threads warten, hat die Operation keine Auswirkung. Es ist nicht in Erinnerung. So ist es möglich, dass Ihr Signalisierungsthread sehr schnell auf 10 zählt und die Zustandsvariable signalisiert, bevor der andere Thread denAufruf erreicht hat.

Sie benötigen eine Schleife um pthread_cond_wait. Die Bedingung muss überprüft werden, falls sie bereits zutrifft, damit der Thread nicht auf eine bereits erfolgte Aufweckung wartet. Und es soll eine Schleife sein, weil Wakeups unecht sein kann: nur weil der Faden fällt durch die pthread_cond_wait bedeutet nicht, dass die Bedingung tatsächlich wahr ist:

while (cont < 10) 
    pthread_cond_wait(&cond, &myMutex); 

Auch gibt es keine Notwendigkeit, ein Thread-Attribut zu erstellen, um einen Thread zusammenfügbar zu machen. Dies ist die Standardsituation, wenn Sie einen Nullzeiger für das Erstellungsattribut verwenden. POSIX-Threads können verbunden werden, es sei denn, sie wurden getrennt erstellt oder mit pthread_detach in losgelöst konvertiert.

Eine andere Sache: wenn möglich, vermeiden Sie pthread_cond_signal anrufen, während Sie eine Mutex-Sperre halten. Es ist nicht inkorrekt, aber es ist möglicherweise verschwenderisch, weil die Operation tatsächlich in den OS-Kernel rufen muss, um einen Thread aufzuwecken, und so halten Sie diese teure Mutex-Sperre über den gesamten Systemaufruf (wenn alles, was Sie wirklich brauchen) schützt einige Maschinenanweisungen, die mit geteilten Daten in Ihrer Anwendung arbeiten).

+0

Ihr anotherThread ruft einfach pthread_cond_wait auf, ohne zuerst zu testen, ob die gewünschte Bedingung (Zähler erreicht zehn) schon passiert ist Ich dachte, Zustandsvariablen funktionieren wie folgt: Wenn die Ausführung pthread_cond_wait erreicht, bleibt der Thread stehen, bis das Signal empfangen wird. Warum muss ich testen, ob die gewünschte Bedingung bereits erfüllt ist, da dies die Aufgabe der Zustandsvariablen ist? Ich meine ... warum brauche ich Zustandsvariablen, da ich einfach eine Schleife machen könnte, um zu testen, ob mein Zustand erreicht ist, und zum Beispiel eine Flagge dafür zu erstellen. und wenn dieses Flag wahr ist, wird der andere Thread beendet. –

+0

Ich habe versucht, die pthread_cond_wait in die Schleife wie Sie sagten, aber es funktioniert immer noch nicht ... http://pastebin.com/tNB9wCMW Ich bin sehr verwirrt, weil ich nicht verstehe, wie Sie die Kontrolle haben Threads, damit die Ausführung pthread_cond_wait vor pthread_cond_signal erreicht Vielen Dank für Ihre Antworten –

+0

Was passiert eigentlich, wenn die Ausführung pthread_cond_wait erreicht. friert es ein, bis das Signal empfangen wird? Wenn ja, warum brauche ich eine while-Schleife und nicht nur eine if-Anweisung? –

2

Ich weiß nicht, was Ihr tatsächliches Problem ist (was passiert, wenn es nicht funktioniert?) ..

Ich sehe ein großes Problem, Sie behandeln nicht die spurious wakeups.

Sie brauchen etwas, das signalisiert, dass die Bedingung wirklich wahr, zum Beispiel mit einer Booleschen Variable:

init:

signaled = false; 

Signal:

signaled = true; 
pthread_cond_signal(&cond); 

erhalten:

while (!signaled) 
    pthread_cond_wait(&cond, &myMutex); 
+0

Das Hauptproblem ist das * verloren * Wake-up, für die Sie eine 'if' um den' pthread_cond_wait' benötigen. Störende Wakeups sind ein kleines Problem, das ein "while" sein muss. Es ist unwahrscheinlich, dass in dieser One-Shot-Situation mit nur zwei Threads ein unechtes Wakeup passiert. – Kaz

+0

yepp, ich sah deine ausgezeichnete Antwort;) –

0

Das ist nur eine Idee, aber Sie könnten auch Semaphoren benutzen, um den "Trigger" zu machen. Ich erinnere mich an ein Projekt, an dem ich vor einer Weile gearbeitet habe und was wir getan haben, während einer unserer Threads darauf wartete, ausgelöst zu werden (mit sem_wait), würde einfach auf eine unendliche Zeit warten, um die Sperre zu bekommen (und wurde somit entfernt) der Proc vom Scheduler und spart wertvolle Zyklen). Sobald der Hauptthread fertig war, würde er die Semaphore freigeben, damit der zweite Thread seine Berechnung durchführen kann.

Dies ist einfach eine andere Alternative.

1

Was Sie wollen, ist ein Semaphor keine Zustandsvariable.

Ein Semaphor behält den Zustand bei und zählt wait() und signals() dagegen.
Es wird normalerweise mit einer Zustandsvariablen implementiert.

Look here für eine triviale Implementierung.

Verwandte Themen