Zwei Threads - Eine globale Variable inkrementieren
-
dachschaden schrieb:
Du hast einen Parameter, dem du einem Thread übergeben kannst. Der ist deine eigene ID. Mit der kannst du arbeiten.
Ich wüsste nicht, bei welchem Parameter ich beim erstellen eine eigene ID auswählen könnte.
int pthread_create (pthread_t *th, pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);
Verzeih mir meine Unwissenheit.
-
Manpage?
man pthread_create schrieb:
The pthread_create() function starts a new thread in the calling process.
The new thread starts execution by invoking start_routine(); arg is passed as the sole argument of start_routine()IOW RTFM.
size_t i; for(i = 0;i < THREADS;i++) pthread_create(&tids[i],NULL,zaehlen,(void*)(uintptr_t)i);
Da hast du deine custom thread ID.
-
dachschaden schrieb:
uintptr_t
Das geht weit über den Stoff hinaus, den wir bisher hatten. Vorerst ist für mich das Thema abgeschlossen und ich nehme die "Deadlocks" erstmal hin, da wir beispielsweise auch keine Semaphoren hatten.
Ich bedanke mich für die Hilfe. Sobald ich wieder Zeit für das Programm habe, setze ich mich dran und beende es, damit deine Hilfe nicht umsonst war.
-
Das ist eine verdammte Typumwandlung, die du in deinem
printf
bereits machst, und die dem Compiler lediglich sagen soll, dass er die Schnauze zu halten hat, wenn ich ihm eine Ganzzahl gebe und er aber einen Zeiger erwartet. Die kannst du auch wegnehmen, aber dann hast du halt Warnungen.
-
dachschaden schrieb:
Ist in unter 60 Zeilen zu schaffen. [...]
EDIT 2: Sogar auf unter 45.unter 45? Ich mach's in 10 ...
#include <omp.h> #include <iostream> main(){ int n; omp_set_num_threads(2); #pragma omp parallel for ordered schedule(dynamic) for(int i = 0; i < 1000; ++i) #pragma omp ordered { std::cout << "Thread " << omp_get_thread_num() << ": " << n << std::endl; ++n; } }
-
C++ und OpenMP, nicht C und pthreads.
Thema verfehlt, 6, setzen.
-
dachschaden schrieb:
Das ist eine verdammte Typumwandlung, die du in deinem
printf
bereits machst, und die dem Compiler lediglich sagen soll, dass er die Schnauze zu halten hat, wenn ich ihm eine Ganzzahl gebe und er aber einen Zeiger erwartet. Die kannst du auch wegnehmen, aber dann hast du halt Warnungen.Danke. Nun funktioniert es.
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #include <inttypes.h> #define LOOP 1500 #define THREADS 2 #define SEMAPHOREN 2 int Increment = -1000; sem_t mutex[2]; void *zaehlen(void *cr) { int i; for(i = 0; i < LOOP; i++) { sem_wait(&mutex[(uintptr_t)cr]); Increment = Increment + 1; printf("Thread: %lu |\t%d\n", (uintptr_t)cr, Increment); sem_post(&mutex[((uintptr_t)cr)+1]); sem_post(&mutex[((uintptr_t)cr)-1]); } return(NULL); } int main(void) { pthread_t threads[THREADS]; sem_init(&mutex[0], 0, 1); sem_init(&mutex[1], 0, 0); size_t i; for(i = 0; i < THREADS; i++) { pthread_create(&threads[i], NULL, zaehlen, (void*)(uintptr_t)i); } for(i = 0; i < THREADS; i++) { pthread_join(threads[i], NULL); } for(i = 0; i < SEMAPHOREN; i++) { sem_destroy(&mutex[i]); } pthread_exit(NULL); return(0); }
Thread: 0 | 1991 Thread: 1 | 1992 Thread: 0 | 1993 Thread: 1 | 1994 Thread: 0 | 1995 Thread: 1 | 1996 Thread: 0 | 1997 Thread: 1 | 1998 Thread: 0 | 1999 Thread: 1 | 2000
#EDIT
Ja, funktioniert nicht für >2 Threads, aber mehr hat die Aufgabenstellung auch nicht verlangt und ich brauche erst mal eine Pause für heute.
#EDIT2
Vielen Dank, dachschaden!
-
dachschaden schrieb:
C++ und OpenMP, nicht C und pthreads.
Thema verfehlt, 6, setzen.LOL
Die Aufgabe besteht daraus, zwei Threads abwechselnd eine globale Variable (Increment) jeweils um 1 zu inkrementieren."
Da steht nix von OpenMP verboten.
-
sem_post(&mutex[((uintptr_t)cr)+1]); sem_post(&mutex[((uintptr_t)cr)-1]);
Fehler, du greift hier auf Elemente zu, die du nicht reserviert hast. Dass das funktioniert ist reines Glück.
Du musst das nächste Element, welches du freigibst, ordentlich ermitteln:
void*zaehlen(void*cr) { uintptr_t id = (uintptr_t)cr,id_next = ((id + 1) == THREADS ? 0 : id + 1); while(1) { sem_wait(&sem[id]); if(Increment == LOOP) break; ++Increment; printf("Thread: %lx|%lx|\t%d\n",id,id_next,Increment); sem_post(&sem[id_next]); } sem_post(&sem[id_next]); return NULL; }
So greifst du niemals auf ungültige Elemente zu.
versionsnummer schrieb:
Da steht nix von OpenMP verboten.
Das Beispiel zielt darauf ab, dass derjenige, der die Aufgaben erhalten hat, begreift, was es mit Synchronizität zu tun hat und wie man kritische Sektionen erkennt und mit ihnen umgeht. Dein OpenMP-Beispiel umgeht diesen Lerneffekt. Damit hast du das Thema verfehlt. Ich bleibe dabei, 6, setzen.
Außerdem: warum überhaupt C++ und OpenMP? Ich dachte, die haben jetzt diese schmucken Futures, die vom Standard unterstützt werden (und die in der Realität langsamer sind als OpenMP, aber die Ausrede lasse ich nicht gelten).
EDIT: Nee, die sind langsamer, nicht schneller. Einfach deswegen, weil die sich entscheiden können, es eben doch nicht async zu machen, sondern nur deferred, und weil C++ eh besondere Flaschenhälse. Stattdessen muss man dann 3rd-Party-Zeugs verwenden oder sein Threadpooling doch selbst machen.
-
dachschaden schrieb:
So greifst du niemals auf ungültige Elemente zu.
Sehr cool, vielen Dank!
dachschaden schrieb:
id_next = ((id + 1) == THREADS ? 0 : id + 1);
Die Operationen sind mir auch neu.
Ich weise id_next also einem Wert zu, wenn (id + 1) gleich einer Zahl aus der Schleife von 0 bis THREADS ist, wobei id immer um 1 erhöht wird?
-
Addiere auf
id
temporär 1, prüfe, ob dies gleichTHREADS
ist (also ein inbound-Check). Wenn dem der Fall ist, sind wir der Letzte in der Liste, und den Semaphore, den wir freigeben wollen, ist dann der erste - der hat den Index 0. Wenn wir nicht der Letzte in der Liste sind, dann nehmen wir einfach das nächste Element. 0 oder das nächste Element (id + 1
) wird dann zugewiesen.id
selbst wird nicht um 1 erhöht. Höchstens wird der Wert vonid
genommen, darauf 1 addiert, und dann in der Berechnung verwendet. Hätte man auch hierdurch ersetzen können:uintptr_t id = (uintptr_t)cr; uintptr_t id_next = id + 1; if(id_next == THREADS) id_next = 0;
Aber damit könnte ich dann nicht mehr sagen, dass ich auf unter 45 LOC komme.
-
dachschaden schrieb:
Addiere auf
id
temporär 1, prüfe, ob dies gleichTHREADS
ist (also ein inbound-Check). Wenn dem der Fall ist, sind wir der Letzte in der Liste, und den Semaphore, den wir freigeben wollen, ist dann der erste - der hat den Index 0. Wenn wir nicht der Letzte in der Liste sind, dann nehmen wir einfach das nächste Element. 0 oder das nächste Element (id + 1
) wird dann zugewiesen.id
selbst wird nicht um 1 erhöht. Höchstens wird der Wert vonid
genommen, darauf 1 addiert, und dann in der Berechnung verwendet. Hätte man auch hierdurch ersetzen können:uintptr_t id = (uintptr_t)cr; uintptr_t id_next = id + 1; if(id_next == THREADS) id_next = 0;
Das leuchtet mir ein! Ich bedanke mich nochmal für die Hilfe!