QThread richtig einsetzen



  • Saheb schrieb:

    Nein Parallesieren möchte ich das nicht.
    Mir ist wichtig, dass die Threads synchronisiert sind.

    Das Widerspricht sich. Natürlich kannst du mehrere Threads synchronisieren. Aber trotzdem laufen die parallel. Wenn du keine Parallelisierung haben möchtest, benötigst du keine Threads.
    Es bringt keinen Vorteil, wenn du aus deinem Hauptprogramm einen Thread startest um dann direkt im Hauptprogramm darauf zu warten, dass der Thread fertig wird.

    VISA scheint mir eine Kommunikations API zu sein. Ich habe damit noch nichts zu tun gehabt und habe auch nicht vor jetzt die Spezifikation zu lesen. Ich kann mir aber nicht vorstellen, dass die mehrere Threads erwartet.



  • Sorry
    natürlich sind mehrere Thread zusammen gestartet abgesehen von der Hauptthread "GUI".
    Ja VISA ist eine Kommunikation API.



  • An jeder Stelle wo du die Threads mit dem CAgilentLan in mehreren Threads ausführen willst, wirst du dann die Threads erstellen müssen und mit moveToThread eben den Thread an das Objekt übergeben.

    Wenn du potentiell 15 Stellen hast an denen das vokommt, dann eben an 15 verschiedenen Stellen. Eventuell musst du auch nicht immer neue Threads erzeugen, sondern kannst Threads wieder verwenden.

    Aber wenn du 15 Stellen im Code hast, wo du die Sachen ausführst, klingt das für mich so, als ob man das geschickter Designen kann. Aber das ist eine andere Frage und hat mit QThreads nichts zu tun 😉



  • Hi,

    vielen vielen dank für deine Unterstützung.

    Schlangenmensch schrieb:

    Aber wenn du 15 Stellen im Code hast, wo du die Sachen ausführst, klingt das für mich so, als ob man das geschickter Designen kann.

    Welce Design Pattern hätte man nehmen soll (nur zu Info).



  • Saheb schrieb:

    Welce Design Pattern hätte man nehmen soll (nur zu Info).

    Das kann ich nicht beantworten, ohne genauere Informationen über das gesamte Projekt zu haben. Das würde hier deutlich zu weit gehen.
    Aber an 15 verschiedenen Stellen unterschiedliche Instanzen einer recht Zentralen Klasse zu haben ist doch eher ungewöhnlich.

    Hast du viele Klassen, die einen CAgilentLan als Member haben? Dann würde sich vlt. Vererbung anbieten.
    Möglicherweise auch ein strikteres objektorientiertes Design (SOLID)... es gibt viele Möglichkeiten und die können alle richtig oder total falsch sein.



  • Schlangenmensch schrieb:

    Hast du viele Klassen, die einen CAgilentLan als Member haben?

    In noch eine Klasse wird die CAgilentLan verwendet.



  • Hallo,

    wie gesagt da ich bei eine Klasse das Objekt CAgilentLan mehr als 15 mal aufrufe und jedes mal wird eine Verbindung zu Agilent hergestellt und wieder geschlossen und beim nächsten Aufruf das gleiche wieder : Verbindung hergestellt und wieder zu und..... was auch sehr viel Zeit kostet, die für das Endtest spürbar ist.

    Meine Frage ist: Kann ich diese Aufruf Zentral machen?

    Mit dem Aufruf meine ich das hier:

    QThread* thread = new QThread;
    CAgilentLan* worker = new CAgilentLan(/*Argumente nicht vergessen */);
    worker->moveToThread(thread);
    connect(thread, SIGNAL (started()), worker, SLOT (AgilentStart()));
    thread->start();
    

    Danke



  • Das lässt sich bestimmt optimieren. Aber sowas ist schwer allgemein zu beschreiben.

    Sind das unterschiedliche Agilents zu denen du eine Verbindung aufbaust. Bestehen mehrere Verbindungen Zeitgleich?

    Wenn du immer zu dem selben Agilent eine Verbindung benötigst könntest du eine (oder je nach dem wie viele du brauchst) Instanz von CAgilentLan als Member einführen und im Konstruktor die Verbindung aufbauen und im Destruktor wieder schließen. Eventuell musst du dann aber überprüfen ob der Agilent die Verbindung abgebrochen hat, bevor du Daten überträgst.



  • Schlangenmensch schrieb:

    Das lässt sich bestimmt optimieren. Aber sowas ist schwer allgemein zu beschreiben.

    Sind das unterschiedliche Agilents zu denen du eine Verbindung aufbaust. Bestehen mehrere Verbindungen Zeitgleich?

    Ja Sie sind mehrere Agilents.
    Es wird softwaremässig validiert, um welche Agilent sich handelt mitder entsprechenden richtige Commando ja nachdem um welchen Task sich handelt (RUN,STOP Trigger......).
    Nein es ist nicht möglich mehrere Verbindung Zeitgleich.

    Schlangenmensch schrieb:

    Wenn du immer zu dem selben Agilent eine Verbindung benötigst könntest du eine (oder je nach dem wie viele du brauchst) Instanz von CAgilentLan als Member einführen und im Konstruktor die Verbindung aufbauen und im Destruktor wieder schließen.

    Eventuell musst du dann aber überprüfen ob der Agilent die Verbindung abgebrochen hat, bevor du Daten überträgst.

    Ja das mache ich auch
    Da die Agilent als Option gedacht wurde und in der GUI mit einem Flag vorgesehen.
    Das heisst: wenn einen Häkchen (Agilent Verbindung ist gefordert)gesetzt ist,wird dann dafür gesorgt dass eine Verbindung hergestellt wird.

    Meine Frage kann ich diese Aufruf der Agilent zentral erstellen, damit es nicht jedesmal eine neue verbindung aufgebaut wird.
    Idee: damit kann ich einbisschen Zeit gewinnen.



  • Idee ist eine Singleton design pattern.

    Was sagst du dazu?



  • Erklär mal, warum du meinst, dass ein Singleton dafür geeignet ist.

    Ich persönlich bin nicht der größte Freund von Singletons. Sie haben ihre Berechtigung, aber nicht überall.



  • Somit kann ich sichergehen, dass nur einen Objeckt von CAgilentLan erzeugt wird.
    Ich muss nicht jedes Mal eine neue Objeckt erzeugen.
    Mir geht es darum am meisten um den Code efiizienter zu gestalten und vorallem die Zeit der Zugriffe auf der Agilent zu reduzieren.

    Der ist Stand: z.B: Wird es 100 mal mit der Agilent kommuniziert (Im sinne von Commando verschicken Screnshot gespeichert und .....), dann wird jedes mal eine neue Verbindung aufgebaut.

    Grosse Nachteil ist, dass dieses Objeckt global verfügbar ist (Es entspricht nicht der Sinn der Object orientierte Programmierung).



  • Darf es denn nur eine Instanz davon geben? Wenn ja kannst du das als Singleton implementieren. Für mich klingt das aber nach einem Ersatz für eine globale Variablen und das ist keine gute Idee.
    Wenn du den Agilenten nur in einer Klasse benutzt, nimm doch einfach eine Member Variable. Dann hast du in der Klasse auch nur eine Instanz, aber kein Ggobales Objekt.



  • Schlangenmensch schrieb:

    Darf es denn nur eine Instanz davon geben?

    Ich bin immer noch nicht zu 100% sicher.Problem ist: wenn die Verbindung aus irgenwie einen grund unterbrochen wird, muss dann die SW neue gestartet werden um die Verbindung wieder zu herstellen.



  • Wenn es nur eine Verbindung geben darf, wäre ein Singleton eine Mögliche Lösung.

    Aber da du bisher mehrere Objekte von dem Typen benutzt, kann ich mir das nicht vorstellen, daher würde ich an deiner Stelle kein Singleton benutzen. Wie ich bereits schrieb, kannst du auch so auf nur einer Instanz der Klasse arbeiten.

    Verbindungsabbrüche musst du abfangen. Ob du jetzt ein Singleton verwendest, oder nur so eine Instanz. Wenn die Verbindung unterbrochen wird, muss die neu aufgebaut werden. Das geht aber auch ohne einen kompletten Programm Neustart.



  • Hi,

    ich bin deine Vorschlag umgesezt in dem ich von CAgilentLan einen membervariable erstellt habe:

    CAgilentLan* m_workerObject;
    

    dann habe ich der Konstruktor der Klasse, wo der Object "CAgilentLan" gebraucht folgende geschrieben:

    QThread * workerThread = new QThread();
    	workerObject = new CAgilentLan(settings_l.strfuGetIP_DSO(), 500, settings_l.bofuGetSimulate());
    	workerObject->moveToThread(workerThread);
    
    	connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
    	connect(workerThread, &QThread::finished, workerObject, &CAgilentLan::deleteLater)
    

    bei der destruktor der Class habe ich folgende:

    if(m_workerObject != NULL)
    	{
    		delete m_workerObject;// hier knallt
    	}
    

    ich bekomme folgende Fehlermeldung:

    ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 9c03e8. Receiver '' (of type 'QNativeSocketEngine') was created in thread 4c3a838", file kernel\qcoreapplication.cpp, line 541
    


  • Diese Error tritt sobald die Application beendet wird.



  • Hi,

    wenn du den Thread auch im Konstruktor erstellst, würde ich daraus auch eine Member Variable machen. Du möchtest den ja hinterher mit

    workerThread -> start();
    

    aufrufen. Und das geht nur, wenn der Thread an der Stelle des aufrufes bekannt ist.

    Der Grund für die Assertion ist das du delete aufrufst, das Objekt aber inzwischen im Thread Context lebt. Außerdem hast du mit deleteLater das Objekt schon zum löschen freigegeben, nach dem finished aufgerufen wird (also the Thread beendet wurde).

    Da ich hier grade keine QT Installation zum ausprobieren habe, gibt mir Google für das Connect aber folgende Syntax:

    QThread * workerThread = new QThread();
    workerObject = new CAgilentLan(settings_l.strfuGetIP_DSO(), 500, settings_l.bofuGetSimulate());
    workerObject->moveToThread(workerThread);
    
    connect(workerObject , SIGNAL(finished()), workerObject , SLOT(deleteLater()));
    connect(workerThread , SIGNAL(finished()), workerThread , SLOT(deleteLater()));
    

    Das heißt, wenn der Thread das SIGNAL finished() schickt, werden die Objekte zum löschen freigegeben. Das übernimmt dann QT und muss nicht nochmal von Hand im Destruktor gemacht werden.
    Wenn du den Thread und den CAgilentLan in der Klasse häufiger verwenden willst, darfst du sie nicht mit dem ersten "finished" Signal löschen.



  • Schlangenmensch schrieb:

    connect(workerObject , SIGNAL(finished()), workerObject , SLOT(deleteLater()));
    connect(workerThread , SIGNAL(finished()), workerThread , SLOT(deleteLater()));
    

    Das ist noch die "alte" syntax. Mit Qt5 wurde die syntax erweitert damit man auch signale z.b. mit einem lambda verknüpfen kann:
    https://woboq.com/blog/new-signals-slots-syntax-in-qt5.html



  • Argh, my fault... das kommt davon wenn man nicht aufpasst und Google noch schnell QT 4.x Dokus raus haut.


Anmelden zum Antworten