R2woD2wo
Anmeldungsdatum: 5. Mai 2016
Beiträge: 132
|
Hallo, frage mich gerade, wie kann man von C oder auch C++ aus eine parallelisierbare Aufgabe auf die Kerne des Prozessors oder der Grafikkarte verteilen? Dabei wäre es schön, das Rechenergebnis in einem gemeinsamem Speicherbereich gelegt zu bekommen - statt mit Dateischnittstellen die Festplatte zu ruinieren (wäre meine Erwartung). Geht das? Oder ist man auf fork o.ä. angewiesen? Beispielaufgabe: Es soll für unterschiedliche Punkte der Funktionswert parallel berechnet und die Ergebnisse in einem Array abgelegt werden: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 | // Meta-C: Kein Lauffähiger Code... zur Illustration...
void FunktionQuadrat(double x, double *erg){
*erg=x*x+1;
return;
}
main(void){ // Hauptprogramm, dass die Prozesse startet.
double x[10];
double y[10];
unsigned int i=0;
// Initialisiere x-Punktemenge:
do{
x[i]=0.1*i;
i++;
}while(i<10);
// Weise Berechnung CPU-Kernen zu:
unsigned int NKerneVerfuegbar=GetFreieKerne(); // GetFreieKerne gibt zurück, wie viele Kerne auf System verfügbar sind.
i=0;
if (NKerneVerfuegbar>0){
do{
WeiseFunktionsJobEinemKernZu(FunktionQuadrat(x[i],&(y[i]));
i++;
while(GetFreieKerne()==0);// Wartezeit, falls es keinen "Job-Stack" für die Kerne gibt.
}while(i<10);
while(GetFreieKerne()<NKerneVerfuegbar);// Wartezeit, bis alle Kerne fertig sind.
// Nun liegt im Array y das Ergebnis der Funktion f(x)=x*x+1 mit x {0,0.1,0.2,..0.9}
} else {
printf("Mist, kann Job nicht Parallelisieren, berechne seriell...");
...
}
}
|
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
R2woD2wo schrieb:
frage mich gerade, wie kann man von C oder auch C++ aus eine parallelisierbare Aufgabe auf die Kerne des Prozessors oder der Grafikkarte verteilen? Dabei wäre es schön, das Rechenergebnis in einem gemeinsamem Speicherbereich gelegt zu bekommen - statt mit Dateischnittstellen die Festplatte zu ruinieren (wäre meine Erwartung).
Das Mittel der Wahl sind Threads. In C nimmt man pthreads und in C++ gibt es mittlerweile die Klasse std::thread im Standard.
Beispielaufgabe: Es soll für unterschiedliche Punkte der Funktionswert parallel berechnet und die Ergebnisse in einem Array abgelegt werden:
Das ist ja grausam ohne Einrückung. Wenn Du Threads nutzt, musst Du Zugriffe auf geteilten Speicher (das Array in dem Beispiel) synchronisieren, damit das Programm thread-sicher ist. Siehe z.B. mutex.
|
Dakuan
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Geht das? Oder ist man auf fork o.ä. angewiesen?
Im Prinzip geht das. Mich beschäftigt das auch schon seit einiger Zeit. Allerdings hatte ich noch nicht die Zeit, mich ausgiebig damit zu beschäftigen, da sich immer andere Probleme vor gedrängelt hatten. Ich hatte das bisher nur zweimal versucht und nur die C Variante hatte richtig funktioniert. Es soll für unterschiedliche Punkte der Funktionswert parallel berechnet und die Ergebnisse in einem Array abgelegt werden:
Da würde ich fork() ausklammern. Da bieten sich Threads an, da die den selben Adressraum belegen. Das ist allerdings auch nicht unproblematisch, da der Zugriff synchronisiert werden muss. Relevante Suchbegriffe: Threads, Threadpool, Mutex ... Ich hatte mir vor einiger Zeit zur Einarbeitung in das Thema das Buch "C++ Concurrency in Action" (Anthony Williams) besorgt, konnte aus Zeitmangel aber nur die ersten Kapitel erarbeiten (Ergebnis inzwischen verjährt). Irgendwo da hatte ich auch eine C++ Methode gesehen, mit der man die Anzahl der CPUs ermitteln konnte. Die konnte ich jetzt aber so schnell nicht wieder finden. Das könnte aber interessant sein, um die optimale Anzahl der Threads zu bestimmen. Aber sicherlich können andere User noch bessere Tips geben.
|
R2woD2wo
(Themenstarter)
Anmeldungsdatum: 5. Mai 2016
Beiträge: 132
|
Cool - Danke für die Stichpunkte! Werde Thema am Mittwoch für gelöst markieren, vielleicht hat noch jemand was.
|
noisefloor
Ehemaliger
Anmeldungsdatum: 6. Juni 2006
Beiträge: 29041
Wohnort: WW
|
Hallo, die Stichworte für die Suche mit einer Suchmaschine deines Vertrauens sind "C++ nebenläufige Programmierung" bzw. auf englisch "C++ concurrency" oder "C++ concurrent programming". Das ganze macht i.d. Regel nur Sinn, wenn die Rechnung wirklich lange dauert, also mehr als ein paar Zehntelsekunden. Du hast ja auch einen gewissen Overheat beim Einrichten von neuen Threads und Prozessen. Gruß, noisefloor
|
R2woD2wo
(Themenstarter)
Anmeldungsdatum: 5. Mai 2016
Beiträge: 132
|
Vielen Dank - wollte gerade nachlegen. Die Thread Geschichte ist top - Demobeispiel funktionert auf Anhieb - ein Hoch auf Linux/Ubuntu! Frage bzgl. Spielart - wahrscheinlich in der Nebenläufigkeit erschlagen: Kann man auch komplette Programme in C als Threads von einem Hauptprogramm aus starten und das Ergebnis in einem gemeinsamen Speicher gelegt einsammeln - oder suche ich nach derartigem vergeblich? Vorteil, müsste nicht alles immer wieder kompilieren/kann von unterschiedlichen Hauptprogrammen auf Agenten(~als Thread von aufrufendem Programm arbeitendes Unterprogram) zugreifen. Wieder "Fantasie"-Programme zur Illustration der Frage mit gleicher Aufgabe dem parallelisierten Quadrieren von Zahlenmengen:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | void main(int argc, char argv[]){ // Zur Illustration/nicht lauffähig: "Slave"-Programm welches auf externem Arbeitsspeicher arbeiten soll.
double *x;
double *y;
double summ=0;
unsigned int n_x;
unsigned int n_y;
unsigned int startx=atoi(argv[0]); // Start in Speicherbereich für Agent
unsigned int endx=atoi(argv[1]); // Ende in Speicherbereich für Agent
if (CheckSpeicherbereich("Quadrieragenten",x,y,&(n_x),&(n_y))>0){
// Ok, es wurde ein Speicherbereich gefunden!
unsigned int i=startx;
while(i<=endx){
y[i]=x[i]*x[i]+1;
i++;
}
printf("Quadrate für %d/%d Punkte berechnet.\n",n_x,n_y);
} else {
printf("Mist, Slave Programm hat keinen Speicherbereich 'Fakultaetsagenten' gefunden - breche ab.");
}
}
|
Nun das aufrufende Programm, das Speicherbereich einrichtet und die Programme aufruft:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 | void main(void){
unsigned int n=10000;
double x[n];
double y[n];
unsigned int i=0;
while(i<n){ // Initialisiere Datenpunkte x
x[i]=i*0.1;
i++;
}
SystemIOVarMem("Quadrieragenten",x,y,n,n); // Systemweite deklaration eines Speicherbereichs "Quadrieragenten" in Form der Speicherbereiche x und y, Ok, statt doubles wär Struct-Zeiger geiler ...
i=0;
char Kommandozeilenaufruf[100];
unsigned int startix;
unsigned int endix;
struct Fork_t handler; // Datentyp zur Überwachung der einzelnen Prozesse bzgl. Terminierung.
while(i<n){
startix=i;
endix=i+2000;
if (endix>=n){ endix=n-1; }
snprintf(Kommandozeilenaufruf,99,"./Quadrieragent %d %d",startix,endix);
handle=SystemFork(Kommandozeilenaufruf); // quasi wie system - nur eben dass nicht auf Ende des aufgerufenen Programms gewartet wird.
i+;
}
while (ProzesseFertig(&handler)==0); // Überwache ob alle gestarteten Prozesse fertig sind.
// Alle Nun liegt Rechenergebnis vor.
return;
}
|
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
R2woD2wo schrieb:
Kann man auch komplette Programme in C als Threads von einem Hauptprogramm aus starten und das Ergebnis in einem gemeinsamen Speicher gelegt einsammeln - oder suche ich nach derartigem vergeblich?
Das geht nicht, es sei denn, Du hast den Quellcode und kannst ihn manipulieren. Wenn ein Programm Shared-Memory nutzt, kann da ggf. etwas gehen. Aber da hätte ich nicht viel Hoffnung.
|
Femtom
Anmeldungsdatum: 21. November 2022
Beiträge: 105
|
Für dein ursprüngliches Problem wäre vielleicht OpenMP die einfachste und schnellste Lösung.
|
R2woD2wo
(Themenstarter)
Anmeldungsdatum: 5. Mai 2016
Beiträge: 132
|
OpenMP und MPI - liest sich spannend: https://de.wikipedia.org/wiki/OpenMP bzw. https://de.wikipedia.org/wiki/Message_Passing_Interface Bei OpenMP war jetzt der Weg die Demoprogramme zu starten steinig - allerdings hab ich auch keine Ahnung von Pragmas bzw. tieferer Ahnung der Compilerflags:
| #include <stdio.h>
int main() {
#pragma omp parallel
puts("Hallo, Welt!\n");
return 0;
}
|
lässt sich immerhin mit
| gcc -openmp main.c -o OpenMPDemo
|
compilieren und ./OpenMPDemo liefert
| :~/04_OpenMP_Threads$ ./OpenMPDemo
Hallo, Welt!
:~/04_OpenMP_Threads$
|
Bei einem spannenderen Beispiel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | #include <omp.h>
#include <stdio.h>
int main() {
omp_set_num_threads(4);
#pragma omp parallel for
for (int i = 0; i < 4; ++i) {
const int id = omp_get_thread_num();
printf("Hello World from thread %d\n", id);
// Nur im Master-Thread ausführen
if (id == 0)
printf("There are %d threads\n", omp_get_num_threads());
}
return 0;
}
|
führt mein Compileversuch zu
| :~/04_OpenMP_Threads$ gcc -openmp main.c -o OpenMPDemo
/tmp/ccCfUyNa.o: In Funktion »main«:
main.c:(.text+0x23): Warnung: undefinierter Verweis auf »omp_set_num_threads«
main.c:(.text+0x34): Warnung: undefinierter Verweis auf »omp_get_thread_num«
main.c:(.text+0x57): Warnung: undefinierter Verweis auf »omp_get_num_threads«
collect2: error: ld returned 1 exit status
:~/04_OpenMP_Threads$
|
Was bewirken eigentlich die Schalter -openmp,-pthread? Bzw. was mach ich falsch/Wo gibt es bessere Tutorials dafür? Hab ein paar englische gefunden, aber die taugen nichts... hingerotzt, unvollständig - offensichtlich für lehrbegleitende Unterlagen gedacht, aber immerhin hab ich hier den Schalter -openmp zum kompilieren gefunden (jedoch mit einem icc Compiler). Das Beispiel zu MPI scheitert daran, dass ich die Bibliothek <mpi.h> scheinbar nicht habe - wie bekomme ich die installiert?
|
Femtom
Anmeldungsdatum: 21. November 2022
Beiträge: 105
|
Ich habe schon lange nichts mehr mit OpenMP oder MPI gemacht und kann da nicht richtig weiterhelfen. Aber für gcc/g++ ist das richtige Flag -fopenmp. Wenn die schriftlichen Tutorials nicht so gut sind, gibt es vielleicht Videos dazu, die besser sind.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
R2woD2wo schrieb: Das Beispiel zu MPI scheitert daran, dass ich die Bibliothek <mpi.h> scheinbar nicht habe - wie bekomme ich die installiert?
Wenn du die libopenmpi aus den Paketquellen nutzt, musst du das Entwicklungspaket libopenmpi-dev installieren: https://packages.ubuntu.com/jammy/libopenmpi-dev
|