QThread richtig einsetzen



  • Hi,

    vielleicht hilft dir die Seite: https://wiki.qt.io/QThreads_general_usage weiter.

    Kurz zusammengefasst, an der Stelle, an der du CAgilentLan erzeugst und aufrufst muss du einen QThread erzeugen, mit moveToThread das Objekt in den Thread "schieben" und dann eben die Verbindung zwischen Signal und Slot herstellen.

    Also ungetestet hast du dann irgendwo sowas

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

    Was hier noch fehlt ist das warten auf Beendigung des Threads (z.B. über ein Signal) und das löschen des Threads und CAgilentLan. Hierfür stellt QT für QObjects die Funktion QObject::deleteLater() bereit.



  • Hallo,

    vielen dank für die Antwort.

    Ich habe es noch eine Frage:

    Schlangenmensch schrieb:

    an der Stelle, an der du CAgilentLan erzeugst und aufrufst muss du einen QThread erzeugen....

    Diesem satz habe ich nicht genau verstanden.

    Bei jeden aufruf dieses Object CAgilentLan muss ich bei der betroffene Class in der Konstruktor sowas schreiben:

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

    oder verstehe ich das falsch?

    Sorry noch mal



  • An wie vielen Stellen hast du das denn?

    Jedes mal, wenn du ein Objekt der Klasse CAgilentLan in einem extra Thread ausführen möchtest, benötigst du sowas in der Richtung.

    Das muss nicht im Konstruktor sein.

    Die Frage, die sich mir nach wie vor stellt ist, was genau willst du parallel ausführen.

    Willst du mehrmals CAgilentLan::AgilentStart() parallel ausführen (wenn ich mich richtig erinnere gabs da Netzwerkverbungen)? Oder was ist deine Idee hinter der Parallelisierung.

    Edit: Zu früh um richtig zu schreiben.



  • Schlangenmensch schrieb:

    An wie vielen Stellen hast du das denn?

    Bei eine Klasse habe ich das in mehreren Stellen (15 mal).

    Jedes mal, wenn du ein Objekt der Klasse CAgilentLan in einem extra Thread ausführen möchtest, benötigst du sowas in der Richtung.

    Das muss nicht im Konstruktor sein.
    [quote="Schlangenmensch"
    Die Frage, die sich mir nach wie vor stellt ist, was genau willst du parallel ausführen.
    [/quote]
    Während es mit der Agilent kommuniziert ist, müssen die anderen Thread warten.

    Schlangenmensch schrieb:

    Willst du mehrmals CAgilentLan::AgilentStart() parallel ausführen (wenn ich mich richtig erinnere gabs da Netzwerkverbungen)? Oder was ist deine Idee hinter der Parallelisierung.

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

    Was ich eigentlich für die Zukunft habe, ist der jetzigen Stand der CAgilentLan class zu erweitern in dem ich die VISA "https://en.wikipedia.org/wiki/Virtual_Instrument_Software_Architecture" Standard zu benutzen.
    Grund für diese Umstieg: Der jetzigen Stand dauert sehr lange, wenn es stets eine neue Verbindug aufgebaut ist.



  • 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
    

Anmelden zum Antworten