Wenn Sie nur demonstrieren wollen, dass ein pthread_join
eine Sackgasse führen kann, Sie etwas ähnliches wie dem folgenden Code tun könnte:
#include <stdio.h>
#include <pthread.h>
void* joinit(void* tid)
{
printf("In %#x, waiting on %#x\n", pthread_self(), (*((pthread_t*)tid)));
pthread_join((*((pthread_t*)tid)), NULL);
printf("Leaving %#x\n", pthread_self());
return NULL;
}
int main(void)
{
pthread_t thread1 = pthread_self();
pthread_t thread2;
pthread_create(&thread2, NULL, joinit, &thread1);
joinit(&thread2);
return 0;
}
Dies wird die Haupt-Thread verursachen auf der erzeugte Thread zu warten und Der generierte Thread, der auf den Hauptthread wartet (was zu einem garantierten Deadlock führt), ohne dass zusätzliche Sperr-Primitive erforderlich sind, um das, was Sie demonstrieren möchten, zu überladen.
Und einige Ihrer Fragen mehr direkt zu beantworten:
es sagt: ‚EINVAL‘ (ungültiges Argument), weil thread2
noch nicht, wenn pthread_create
für thread1
angegeben wird aufgerufen wird.
... und von einem Ihrer Kommentare ...
habe ich versucht, diese und es funktioniert, aber das Problem ist, es funktioniert nur manchmal manchmal, weil ich EINVAL wieder bekommen.
In Ihrem Code, rufen Sie pthread_create
nacheinander die zwei Threads zu erstellen:
pthread_create(&thread1, NULL, joinit, &thread2);
pthread_create(&thread2, NULL, joinit, &thread1);
In Ihrem joinit
Code, greifen Sie den Thread-Handle übergeben verbinden auf:
pthread_t* tid_c = (pthread_t*)tid;
int retval = pthread_join(*tid_c, NULL);
Der Grund dafür manchmal funktioniert und andere, die Sie erhalten EINVAL
hat mit time slices zu jedem Threa zugeordnet zu tun d's Kontext und sequencing. Wenn der erste pthread_create
aufgerufen wird, haben Sie nach der Rückgabe ein gültiges Handle zu aber der Handle zu thread2
ist noch nicht gültig, zumindest nicht bis der 2. pthread_create
aufgerufen wird.
Wenn ein Thread erstellt wird, kann die Handlung des Threads, der "lebendig" wird (d. H. Die tatsächlich ausgeführte Thread-Funktion), zusätzliche Zeit beanspruchen, obwohl das zurückgegebene Thread-Handle gültig ist. In diesen Fällen besteht die Möglichkeit, dass ein Thread mehr Code ausführen kann als erwartet.In Ihrem Code, beide pthread_create
Funktionen könnte zufällig in der Zeitscheibe genannt wurden für den Haupt-Thread zugeordnet, die jeweils genug „Zeit“, bevor man die pthread_join
Anweisung ermöglicht tid_c
auf einen gültigen Griff Punkt erzeugte Thread geben könnte; Im EINVAL
Fall wurde pthread_create(&thread1, NULL, joinit, &thread2)
aufgerufen und der erzeugte Thread traf die pthread_join(*tid_c, NULL)
, bevorpthread_create(&thread2, NULL, joinit, &thread1)
thread2
ein gültiges Handle geben konnte (verursacht den Fehler).
Wenn Sie Ihren Code ähnlich halten wollte, wie es jetzt ist, würden Sie brauchen eine Sperre von einer Art hinzufügen, um die Fäden zu gewährleisten, nicht oder rufen Sie vorzeitig alles verlassen:
#include <stdio.h>
#include <pthread.h>
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void* joinit(void* tid)
{
/* this can be above the lock because it will be valid after lock is acquired */
pthread_t* tid_c = (pthread_t*)tid;
int retval = -1;
pthread_mutex_lock(&lock);
pthread_mutex_unlock(&lock);
printf("%#x waiting on %#x\n", pthread_self(), *tid_c);
retval = pthread_join(*tid_c, NULL);
printf("In joinit: tid = %d, retval = %d \n", *tid_c, retval);
return NULL;
}
int main()
{
pthread_t thread1;
pthread_t thread2;
/* get the lock in the main thread FIRST */
pthread_mutex_lock(&lock);
pthread_create(&thread1, NULL, joinit, &thread2);
pthread_create(&thread2, NULL, joinit, &thread1);
/* by this point, both handles are "joinable", so unlock */
pthread_mutex_unlock(&lock);
/* can wait on either thread, but must wait on one so main thread doesn't exit */
pthread_join(thread2, NULL);
return 0;
}
Hope this kann helfen.
habe ich versucht, diese und es funktioniert, aber das Problem ist, es funktioniert nur manchmal, weil ich manchmal EIVAL wieder zu bekommen. ICH überprüfe errno in der Methode joinit! –
Ja, Sie können nicht entscheiden, wann ein Thread gestartet wird, das OS tut das. –
Ja, ich weiß. Ich muss eine zuverlässige Deadlock-Situation haben. –