Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

07.07.2015, 20:25

boost::thread funktion mit funktionszeiger als argument

Hallöchen,

ich versuche gerade eine cminpack(link zu der Seite von cminpack http://devernay.free.fr/hacks/cminpack/) Funktion parallel laufen zu lassen, doch es funktioniert leider nicht.

Im Normalfall, würde ich die Funktion wie folgt aufrufen: __cminpack__func(lmdif1)(fcn, (list of other arguments such as int and double...)). Lmdif1 bedeutet, dass ich den Levenberg-Marquardt(LM-) Algorithmus für mein Problem
nutzen möchte. __cminpack__func ist wie ich deuten kann (bin nämlich eigtl C#-Programmierer muss aber für meine Bachelorarbeit C++ verwenden) ein Makro, dass die entsprechende Funktion dann richtig aufruft. Der LM-Algrorithmus braucht, damit er funktionieren kann, eine Funktion - hier fcn genannt - und noch ein paar eher uninteressante weitere Parameter überwiegend integers und doubles bzw. pointer zu denen.

Nun ja, das oben läuft auch richtig, nun wollte ich das ganze aber mit boost::thread wie folgt parallelisieren:

boost::thread t;

t.start_thread(__cminpack__func(lmdif1),fcn, (...further arguments, same as above))

das funktioniert leider nicht. Genauso wie andere versuche mit ThreadGroups und boost::bind etc... Immer sagt er mir, dass die Argumentenlisten nicht übereinstimmen, obwohl sie dies eigentlich sollten :(( bin schon am verzweifeln...

Deshalb wollte ich mal fragen, ob das denn überhaupt möglich ist, eine Funktion in einem Thread zu übergeben, wobei die übergebene Funktion als Argument selbst eine Funktion entgegen nimmt?

Ich konnte leider auch im Netz nichts wirklich hilfreiches finden. Immer kamen Beispiele mit gewöhnlichen Argumenten....

Wäre super, wenn mir jemand helfen könnte :)

Danke im voraus!

Gruß,
CSharp

2

07.07.2015, 22:27

Ich hab Minpack nie benutzt, aber notfalls solltest du doch eigentlich auch irgendwie eine Wrapper-Funktion schreiben können, die du dann an boost::thread übergibst.

Wenn du einen modernen C++ Kompiler hast, kannst du außerdem einfach std::thread benutzen. Sollte genau so funktionieren, braucht dann aber kein boost mehr. Und du könntest dir evtl. std::function angucken, mit rohen Funktionszeigern in C++ zu hantieren macht einfach nicht so viel Spaß wie die moderneren Varianten.
Lieber dumm fragen, als dumm bleiben!

Schrompf

Alter Hase

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

3

07.07.2015, 22:49

Wenn Du boost nimmst, dann mach es mit boost::bind()

Quellcode

1
std::thread t( boost::bind( &YourFunction, zahl, beispiel));


Wenn Du komplett std-seitig bleiben willst, nimm ne Lambda-Funktion

Quellcode

1
std::thread t( [&]() { doStuff( variableFromOuterScope, 1); });


Oder Option Drei: std::async() - ist unter GCC/CLang und deren gemeinsamer stdlib allerdings noch buggy, funktioniert nur mit Visual Studio vernünftig.
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

4

08.07.2015, 13:19

Vielen Dank für die schnelle Hilfe! :)

Ich habe mich für deine 2. Lösung entschieden Schrompf, d.h. für die Lambda Funktion, jedoch mit boost::thread (es geht damit genau so 1:1^^).

Leider musste ich feststellen, dass es kaum schneller eher sogar 2 Sekunden langsamer geworden ist und ich dachte, es wäre eine Topidee, um das Ganze performanter zu machen :dash:.
Anscheinend löst Minpack wohl die Optimierungsaufgabe so schnell, dass sich der Threaderzeugungsoverhead kaum lohnt.

So, hab ich es nun realisiert, eventuell mache ich ja etwas ganz falsch, weshalb es langsamer ist:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
inline void MyClass::Optimize(double *P, double *Q, struct FcnData &data){
/* some variable and pointer declarations/definitions here */

boost::thread t;                      //Needed for scoping reasons      

if(Q != nullptr){
     t = boost::thread ( [&] () { __cminpack_func__(lmdif1)(//params for lmdif1 to work...); });           //t could not be used below, if not declared above :( -> Glaube, dass hier das Problem ist, weil der ganze Thread kram kopiert wird oder? Aber weiss auch nicht, was ich sonst tun soll...
}

//do optimization for P if P != null here, i.e. concurrent to optimization of Q, but no thread is created for optimization of P!

if(t.joinable())
  t.join();
}

//somewhere else in the code 
void MyClass::DoWork(){
     do{
       //P,Q and data come from somewhere :)
      //....
      Optimize(P,Q,&data);
     }while(/* optimization of P and Q are not good enough */)
}


Nochmals vielen Dank im voraus :)

Schöne Grüße,
CSharp

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

5

08.07.2015, 14:40

Abgesehen davon gibt es heutzutage std::thread, brauchst also kein boost dafür... ;)

6

08.07.2015, 14:50

Habe boost ohnehin schon includiert, weil ich es noch woanders brauche, ist ja im Prinzip egal :P

Tobiking

1x Rätselkönig

  • Private Nachricht senden

7

08.07.2015, 15:08

Was versuchst du da überhaupt zu parallelisieren? Deine Optimize Funktion ist abhängig vom Ergebnis des vorherigen Durchlaufs. Entsprechend ist die ganze Berechnung rein seriell und nicht parallelisierbar. Und genau das spiegelt dein Code wieder. Er erzeugt zwar einen Thread, aber der Hauptthread wartet nur darauf das dieser Thread fertig wird statt weiter zu laufen (join). Da ist es nicht verwunderlich das es langsamer wird, da du außer der Threaderstellung nichts änderst.

8

08.07.2015, 15:22

Ne, das stimmt nicht ganz, was du schreibst und zwar aus folgendem Grund:

Ich will ja P und Q optimieren. Die Optimierungen sind Unabhängig von einander, d.h. also, dass ich ja eigentlich die Optimierung für Q in einem neuen Thread anschmeißen kann und dann direkt nachdem der Thread gestartet ist, die Optimierung für P starten kann.

Da ich nach der Optimierung der beiden aber beide brauche, muss ich auf den Thread mit dem Q warten, sollte dieser länger brauchen.

Bsp:

opt(P) ||(parallel) opt(Q) sollte eigentlich bessere Ergebnisse liefern als:

opt(Q) //kann nichts machen, solange Q nicht fertig ist, d.h. es wird sinnlos auf das Fertigwerden von Q gewartet
opt(P) //erst wenn Q fertig ist, kann P überhaupt starten

//doWork(P,Q,...)

Schrompf

Alter Hase

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

9

08.07.2015, 15:54

Doch, Tobiking hat Recht. Dein Code tut genau das: er startet die Aufgabe in nem separaten Thread und wartet dann, bis der Thread fertig ist. Du parallelisiert da genau gar nix. Oder zumindest das gepostete Code-Schnipsel tut das.

Was Du eigentlich willst, dürfte folgendes sein:

Quellcode

1
2
3
4
5
6
std::thread t1( [&]() { TuDasEine(); });
std::thread t2( [&]() { TuDasAndere(); });

// dann beide joinen. joinable() kannst Du Dir sparen, das Verhalten ist wohldefiniert für den Fall, dass der Thread bereits fertig ist
t1.join();
t2.join();


Und zumindest mit Visual Studio kannst Du Dir zusätzlich noch die Threaderstellung sparen und stattdessen auf den Threadpool von der C++11-CRT zurückgreifen, indem Du das std::async() überlässt.

Quellcode

1
2
3
4
auto ergebnis1 = std::async( std::launch::async, [&]() { TuDasEine(); });
auto ergebnis2 = std::async( std::launch::async, [&]() { TuDasAndere(); });

ergebnis1.wait(); ergebnis2.wait();


[edit]Oder ich verstehe die Kommentare falsch, die den ausgelassenen Code beschreiben. Kann auch sein. In dem Fall: steppe mal mit dem Debugger durch und guck, wo genau er hängt. Am Ende hat auch die Funktion, die Du da aufrufst, Zugriff auf irgendwelche globalen Sachen und zieht deswegen einen Mutex. Dann nützt Dir alle Parallelisierung nix.
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

10

09.07.2015, 15:44

Hmm okay, da du jetzt der zweite bist, kann es ja sein, dass ich etwas nicht verstanden habe, deshalb erklär ich kurz wie ich das sehe:

Ich habe insgesamt 3 Aufgaben zu erledigen, wobei Aufgabe 1 ist opt(P), Aufgabe 2 ist opt(Q) und Aufgabe 3 ist machEtwasMit(P,Q) hängt somit also davon ab, dass Aufgabe 1+2 fertig sind, damit Aufgabe 3 starten kann.

Wenn ich mein Programm habe, dann habe ich ja default mäßig einen Mainthread.

Wenn ich jetzt in MyClass::Optimize(P,Q) bin, bin ich ja erstmal noch im Mainthread. Wenn ich anschließend einen neuen Thread t eröffne, der Aufgabe 2 bearbeitet, dann kann doch der Mainthread Aufgabe 1 bearbeiten. Wenn jetzt der Mainthread mit Aufgabe 1 fertig ist, jedoch t mit Aufgabe 2 noch nicht, dann wartet der Mainthread einfach auf das Fertigwerden von t mit Aufgabe 2. Sind beide dann fertig, d.h. Aufgabe 1 und 2 fertig, dann wird wieder im Mainthread Aufgabe 3 bearbeitet.

So wie ich jedoch deinen Vorschlag verstehe, soll ich ein Thread t1 für Aufgabe 1 aufmachen, ein thread t2 für Aufgabe 2 und dann im Mainthread darauf warten, dass beide fertig werden, wieso soll ich das tun, da kann doch wie oben beschrieben der mainthread gleich selber die Aufgabe 1 machen und ich spare mir das Erzeugen eines zweiten Threads.

Ich hab es dennoch mal ausprobiert, wie du es vorgeschlagen hast, gibt auch keine Performanceverbesserung.

Aber vielen Dank für die Hilfe :)

Grüße,
CSharp

Werbeanzeige