C++ parallele Rechnungen



  • hfghfghfghfg schrieb:

    Und bei der Parallelisierung betritt man praktisch die Hölle des ganzen Elends. Spätestens hier muss man wissen, was man da tut. Sonst hat man einfach keine Chance. Grundlagen sind da absolut notwendig. Auch zum Thema Parallelisierung gibt es dann wieder neue Grundlagen über Synchronisationen, usw.

    Vielleicht reden wir da wieder aneinander vorbei. Soweit ich das mit meinen bescheidenen Kenntnissen überblicke will ich nicht parallelisieren im Sinne von MPI.

    Ich arbeite mit der MC Methode, d.h. ich benötige (sagen wir) 1000 Durchläufe meines Programms, um anschließend einen sinnvollen Mittelwert zu bilden. Und jetzt will ich einfach sagen können:
    Anstatt 1000 Durchläufe auf einem Kern durchzuführen, kann ich doch auch 250 Durchläufe auf vier Kernen laufen lassen und anschließend mitteln.

    Dabei müssen die Kerne ja keine Informationen austauschen.

    Soweit ich das verstanden habe kann ich bei Linux also auch vier mal eine Konsole öffnen und darin das Programm starten und dann mittels des Befehls top sehen, dass alle vier Kerne ausgelastet sind.

    Gruß,

    Klaus.



  • Dann mach dein C-Programm komplett Singlethreaded und simpel und sammel die Daten erst nachher aus einem Shellscript heraus zusammen.

    Oder war das sogar deine ursprüngliche Frage und wir haben sie falsch verstanden?



  • parallel_for_each aus der ppl.



  • Klaus82 schrieb:

    hfghfghfghfg schrieb:

    Und bei der Parallelisierung betritt man praktisch die Hölle des ganzen Elends. Spätestens hier muss man wissen, was man da tut. Sonst hat man einfach keine Chance. Grundlagen sind da absolut notwendig. Auch zum Thema Parallelisierung gibt es dann wieder neue Grundlagen über Synchronisationen, usw.

    Vielleicht reden wir da wieder aneinander vorbei. Soweit ich das mit meinen bescheidenen Kenntnissen überblicke will ich nicht parallelisieren im Sinne von MPI.

    Ich arbeite mit der MC Methode, d.h. ich benötige (sagen wir) 1000 Durchläufe meines Programms, um anschließend einen sinnvollen Mittelwert zu bilden. Und jetzt will ich einfach sagen können:
    Anstatt 1000 Durchläufe auf einem Kern durchzuführen, kann ich doch auch 250 Durchläufe auf vier Kernen laufen lassen und anschließend mitteln.

    Dabei müssen die Kerne ja keine Informationen austauschen.

    Soweit ich das verstanden habe kann ich bei Linux also auch vier mal eine Konsole öffnen und darin das Programm starten und dann mittels des Befehls top sehen, dass alle vier Kerne ausgelastet sind.

    Gruß,

    Klaus.

    Gibt 3 Möglichkeiten,

    entweder du schreibst ein Programm dass am Anfang 4 Threads startet(Threads können parallel ausgeführt werden) du brauchst dann tatsächlich keine synchronisation weil die threads sich nicht dafür interessieren müssen was die anderen tun. Dann wartest du mit deinem main thread bis deine 3 worker threads fertig sind und mittelst ihre ergebnisse.

    zweit Möglichkeit wäre Kindprozesse mit fork zu erstellen, funktioniert glaube ich danna ber nicht auf windows.

    dritte Möglichkeit is wohl die einfachste. Weil keine synchronisation Notwendig ist kannst du einfach mit einem shell script 4mal dein programm starten, übergibst ihnen über den Komandozeilenparameter den Seed oder suchst dir ne bessere Methode an einen Seed zu kommen. Jetzt wartest du in deinem shell script bis die vier programme fertig sind und mittelst die ausgabe.

    Dazu google:
    wie du die ausgabe des programms in eine variable bekommst um danach damit weiter zu rechnen
    wie du mehrere programme gleichzeitig starten kannst aus einem shell script heraus
    wie du in C/C++ kommandozeilen parameter einliest.

    Das müsstest du alles finden.

    #include <stdio.h>
    #include <stdlib.h>
    #include <iostream>
    
    int main(int argc, char** argv)
    {
    
        int n = atoi(argv[1]);
    
        for(int i = 0; i < n; ++i)
        {
            std::cout << "Hello World" << std::endl;
        }
    
        return 0;
    }
    

    was machst du wenn kein parameter übergeben wurde? Dann gibt es argv[1] gar nicht. Deshalb auch das abfragen.



  • tobZel schrieb:

    wie du mehrere programme gleichzeitig starten kannst aus einem shell script heraus

    Also das habe ich mal ganz banal wie folgt gelöst:

    #!/bin/bash
    
    for (( i=0 ; i<$1 ; i++ )); do
    	./main_water $((i+1)) &
    done
    exit 0
    

    Durch das & Zeichen werden die Prozesse in den Hintergrund geschoben und so wird nicht gewartet, bis der erste Prozess fertig ist.

    tobZel schrieb:

    wie du in C/C++ kommandozeilen parameter einliest.

    Das hatten wir ja schon und ich habe dazu ein Beispiel gegeben, auch wenn es natürlich nicht abfragt, ob der User verstanden hat, wie die Eingabe zu erfolgen hat. 😃

    tobZel schrieb:

    wie du die ausgabe des programms in eine variable bekommst um danach damit weiter zu rechne

    Ja, das steht natürlich noch aus. Bisher habe ich einfach die Eingabe für den n-ten Durchlauf an die Funktion weitergegeben, welche die Daten in Dateien speichert.

    void saving::saving_data(int & number)
    {
      std::ostringstream outfilename;
      outfilename << "data_file_nr" << number << ".dat";
      std::string outfile(outfilename.str());
      std::ofstream ofile(outfile.c_str());
    
      for(long int i = 0; i < n; ++i)
      {
        double j = i * dE;
        ofile << j << "\t\t" << energy[i] / runs << std::endl;
      }	
    }
    

    Irgendwie habe ich den Eindruck,dass eine der beiden Zeilen unnötig ist:

    std::string outfile(outfilename.str());
      std::ofstream ofile(outfile.c_str());
    

    Gruß,
    Klaus.



  • Also das Thema hat mir nach wie vor keine Ruhe gelassen und ich habe mich auch mit dem Buch von Rainer Grimm 'bewaffnet'.

    Ich habe versucht ein Beispiel zu Threading mit Übergabe von Parametern zu kompilieren. Das findet sich z.B. auf der verlinkten Seite unter Downloads .

    Ich habe die Beispieldatei createThreadWithArguments.cpp gekürzt, da mich zunächst nur Funktionen interessieren und keine Funktionen von Klassen bzw. Lambdafunktionen:

    /*
     * createThreadWithArguments.cpp
     *
     *  Created on: 24.04.2011
     *      Author: Rainer Grimm
     *      Book  : C++0x
     */
    #include <iostream>
    #include <string>
    #include <thread>
    
    void helloFunction(const std::string& s){
      std::cout << s << std::endl;
    }
    
    int main(){
    
      std::cout << std::endl;
    
      // thread executing helloFunction
      std::thread t1(helloFunction,"Hello C++0x from function.");
    
      // ensure that t1, t2 and t3 have finished before main terminates
      t1.join();
    
      std::cout << std::endl;
    
    }
    

    Es kompiliert vollständig nur leider kriege ich dann bei der Ausführung einen Speicherzugriffsfehler. 😞

    Wenn ich gdb anwerfe, dann sagt er

    Program received signal SIGSEGV, Segmentation fault.
    0x0000000000000000 in ?? ()
    (gdb) bt
    #0  0x0000000000000000 in ?? ()
    #1  0x00002aaaab3ec5d7 in std::thread::_M_start_thread(std::shared_ptr<std::thread::_Impl_base>) () from /usr/lib/libstdc++.so.6
    #2  0x000000000040127c in main ()
    

    Und Valgrind sagt dazu folgendes:

    ==11149== Command: ./createThreadWithArguments
    ==11149== 
    
    ==11149== Jump to the invalid address stated on the next line
    ==11149==    at 0x0: ???
    ==11149==    by 0x400FCF: ??? (in /var/autofs/home/home/huthmacher/Cpp/sandkasten/createThreadWithArguments)
    ==11149==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
    ==11149== 
    ==11149== 
    ==11149== Process terminating with default action of signal 11 (SIGSEGV)
    ==11149==  Bad permissions for mapped region at address 0x0
    ==11149==    at 0x0: ???
    ==11149==    by 0x400FCF: ??? (in /var/autofs/home/home/huthmacher/Cpp/sandkasten/createThreadWithArguments)
    ==11149== 
    ==11149== HEAP SUMMARY:
    ==11149==     in use at exit: 72 bytes in 1 blocks
    ==11149==   total heap usage: 1 allocs, 0 frees, 72 bytes allocated
    ==11149== 
    ==11149== 72 bytes in 1 blocks are still reachable in loss record 1 of 1
    ==11149==    at 0x4C24DFA: operator new(unsigned long) (vg_replace_malloc.c:261)
    ==11149==    by 0x4011DA: main (in /var/autofs/home/home/huthmacher/Cpp/sandkasten/createThreadWithArguments)
    ==11149== 
    ==11149== LEAK SUMMARY:
    ==11149==    definitely lost: 0 bytes in 0 blocks
    ==11149==    indirectly lost: 0 bytes in 0 blocks
    ==11149==      possibly lost: 0 bytes in 0 blocks
    ==11149==    still reachable: 72 bytes in 1 blocks
    ==11149==         suppressed: 0 bytes in 0 blocks
    ==11149== 
    ==11149== For counts of detected and suppressed errors, rerun with: -v
    ==11149== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
    make: *** [memcheck] Speicherzugriffsfehler
    

    Was kann denn bei so einem einfachen Programm schon schief gehen? Ist mein gcc Kompiler nicht aktuell genug? Ich verwende gcc version 4.4.5 (Debian 4.4.5-8) .

    Gruß,
    -- Klaus.



  • Mit welchen Flags hast du denn kompiliert? Du brauchst -pthread und eine aktuelle GLIBCXX.



  • kompail schrieb:

    Mit welchen Flags hast du denn kompiliert? Du brauchst -pthread und eine aktuelle GLIBCXX.

    Aha, so einfach kann es also sein. Sagt einem ja auch keiner. 😉

    g++ -Wall -pedantic -std=c++0x -O2 -c createThreadWithArguments.cpp
    g++ -Wall -pedantic -std=c++0x -O2 -pthread -o "createThreadWithArguments" createThreadWithArguments.o
    

    Dann funzt es auch. 🙂

    Gruß,
    -- Klaus.


Anmelden zum Antworten