http://en.cppreference.com/w/cpp/language/static
- - - Aktualisiert - - -
Auf einem Pi habe ich ihn nicht getestet, aber in Visual Studio läuft er.
http://en.cppreference.com/w/cpp/language/static
- - - Aktualisiert - - -
Auf einem Pi habe ich ihn nicht getestet, aber in Visual Studio läuft er.
".... und was das für mein PID Problem jetzt eigentlich bedeutet...."
Ohne dir zu nahe treten zu wollen, du schimpfst auf OOP ohne dich damit genau beschäftigt zu haben. Das C++ nunmal anders programmiert wird als C, auch wenn C eine Untermenge von C++ ist, ist nunmal dem geschuldet, dass es eine andere Programmiersprache ist. Und eine andere Programmiersprache muss man eben auch erst mal lernen. Zu einer Programmiersprache gehören eben nicht nur die keywords und die Syntax sondern eben auch Konzepte und Hintergrundwissen bezüglich dem was unter dem Oberfläche passiert.
Mein Vorschlag wäre nimm std::threads in deiner Klasse. Ein std::thread ist unter Linux genau das selbe wie ein thread der über Posix (pthread) gestartet wurde. Wenn du sachen machen willst wie thread abbrechen oder priority ändern. Lässt du dir von dem std::thread sein native handle (Das auch nur ein Verweis auf einen pthread ist) geben und kannst das ganz normal den pthread funktionen übergeben. Der Vorteil dabei ist, du sparst dir eben das etwas komplizierte Aufrufen eines pthreads auf eine Klassenfunktion.
Es beantwortet die Frage.
Statt im obigen Beispiel
müsste man etwas in der ArtCode:std::thread MakeTask() { return std::thread([this] { Control(3); }); }
schreiben. Dann könnte manCode:static void MakeTask(void* this_instance) { ((PidClass*) this_instance)->Control(3); }
Ungetestet und aus dem Kopf geschrieben, zeigt nur das Prinzip.Code:int main() { PidClass pid; pthread_t t; pthread_create(&t, NULL, &PidClass::MakeTask, &pid);
Geändert von Mxt (20.09.2016 um 08:38 Uhr)
ich will doch gar nichts "returnen"...?
ich will doch nur eine Funktion einfügen, die was ausführt, aber nur eben als task-Funktion, nicht als "normale" Funktion...
return ((PidClass*) this_instance)->Control(3);
das hier ist mir allerdings schon wieder komplett unverständlich:
pthread_create(&t, NULL, &PidClass::MakeTask, &pid);
nee, ich gebe es auf, hat keinen Sinn, OOP mit C++ ist wirklich nicht mein Ding.
Ja, da war ein return zu viel.
Hallo HaWe,
also nachdem ich mir dein Mindstrom Code angesehen habe, wäre wohl der erste Schritt Deine Berechnungsroutinen "task_PID_[ABC]" so umzuscheiben, das sie als Parameter einen Zeiger auf eine struct eines PIDs bekommen. Ansonsten landest Du wieder bei der Code-Redundanz, wie Du sie im Mindstorm-Projekt hast.
Das was in dem einfachen Beispiel in der main() steht würdest du halt für jede Motoraktion (Rotate, Continue etc...) durchimplementieren müssen. Auch müßtest Du den Zeiger auf die einzelne struct ordentlich an die anderen Funktionen weiterreichen, damit diese immer nur auf dieser einen Variable operieren und so keine Wettbewerbsbedingungen entstehen.Code:#include <stdio.h> #include <pthread.h> struct PID { pthread_t tid; char* name; float p; float i; float d; }; struct PID pids[] = { {0, "Task A", 0.015, 0.2, 0.7 }, {0, "Task B", 0.3, 0.5, 0.80 } };; /* thread main */ void *calc_pid(void *arg) { struct pid* PID = (struct pid*)arg; int idx = 0; for(idx = 0; idx < 8; idx++) { pid->p += .03; printf("[%d]: %s, p=%f, i=%f, d=%f\n", idx, pid->name, pid->p, pid->i, pid->d); } return 0; } int main(int argc, char** argv) { int idx = 0; int size = sizeof(pids)/sizeof(struct pid); /* Konfig fuer eine Aktion beider Motoren, wie immer die aussehen mag */ for(idx = 0; idx < size; idx++) if(pthread_create(&pids[idx].tid, 0, calc_pid, &pids[idx])) { perror("pthread not creatable "); return 1; } for(idx = size - 1; idx >= 0; idx--) { if(pthread_join(pids[idx].tid, 0)) { fprintf(stderr, "Couldn't join thread for task %s ", pids[idx].name); perror(" "); continue; } pids[idx].tid = 0; } return 0; }
Der Nachteil ist IHMO, dass Threads erzeugt und wieder vernichtet werden, was Resourcen kostet.
Ein anderer Ansatz wäre, für jeden PID einmal einen Thread anzulegen, der aus einer synchronisierten Schlange für einen Motor Kommandos liest, ausführt und zurück meldet das es fertig ist. Dann gäbe es einen Thread der den anderen sagt was zu tun ist - quasi das Kommando über sie hat.
Nachteil hier ist, das Du einen Synchronisationsmechanismus implementieren müßtest.
Auch könntest du dir vielleicht mal die OMP Threading-Variante anschauen, dann hättest du weniger mit Synchronisationsaufwand zu tun und ist möglicher Weise der übersichtlichere Weg für dich.
Das sind so meine Ideen zu deinem Problem.
Gruß
botty
ach ja, gerade erst gecheckt - vlt war es doch noch auch ein Kommunikationsproblem und ich hatte es nicht ausreichend erläutert:
das pid-task create soll nicht von main oder einer anderen Funktion aus, sondern automatisch innerhalb der PID Klasse selber gestartet werden.
Die PID Klasse sollte dafür dann (mindestens) 3 Methoden enthalten,
zum einen eine für den Funktionsaufruf selber ähnlich wie
PID.start(double p, double i, double d, char mode);
PID.start initialisiert damit die p,i,d Konstanten und die Variable Modus (erreichen und dann abschalten oder kontinuierlich halten)
und dann wird damit anschließend ebenfalls die 2. Methode, nämlich
PID.thread
quasi lokal gestartet, nicht global.
später, nach
new PID PID_A;
soll dann alles automatisch laufen durch
Nun läuft der damit intern creierte pthread-Task bis zur Selbstterminierung oder bis zur Beendigung durch einen externen Befehl.Code:PID_A.start(0.5, 10.0, 0.1, true);
die dritte Methode muss dafür lauten
PID.stop();
nach externem Aufruf per
soll dann der momentan laufende PID_A-Task mit seiner momentan vergebenen PID-ID gestoppt und dann gejoint werden (falls er tatsächlich läuft, ansonsten wirkungslos).Code:PID_A.stop();
analog das ganze für jede andere erzeugte und dann bei Bedarf gestartete PID-Instanz
new PID PID_B;
new PID PID_C;
new PID PID_D;
new PID PID_E;
usw.
Wo der Thread gestartet wird macht keinen großen Unterschied. Bei std::thread würde sich am eigentlichen Code nichts ändern.
Beim Beispiel mit dem static member nur zwei Dinge:
undCode:class PidClass { private: pthread_t t; // Ist jetzt in der Klasse, statt in main
Code:pthread_create(&t, NULL, MakeTask, this); // Wenn in einem Member der Klasse verwendet
Geändert von Mxt (20.09.2016 um 15:19 Uhr) Grund: & kann auch weg
Lesezeichen