Solved QThread richtig einsetzen?
-
@J-Hilk
Auf eine kurze Antwort werde ich mich freuen. -
@Galilio
Hi, guten Morgen,ich war leider die Woche sehr beschäftigt auf Arbeit.
Zu deiner Frage,
deine Worker-Klasse wird, so wie man es auch machen soll, im Main-Thread erstellt und anschließend in dem Thread übergeben.Das bedeutet aber auch das alle Objekte im Constructor die du ohne parent erstellst, z.B. der TCPSocket, werden nicht automatisch mit verschoben.
Also entweder alles im Worker Constructor in einer Funktion ausführen, die nachthread started
aufgerufen wird, oder die Objecte ebenfalls mit moveToThread dem QThread object übergeben. -
danke für die Antwort.
Ich brauche aber wirklich deine Hilfe.
Egal wie ich das implementiere.
Ich bekomme stets diese Fehlermeldung:ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 860030. Receiver '' (of type 'QNativeSocketEngine') was created in thread 490ef60", file kernel\qcoreapplication.cpp, line 541
Ich weiss es nicht was ich denn falsch mache...................
Vielen Dank in voraus -
Hallo,
ich bin einfach zurück zu deinem erstellten demo ThreadProjekt, die du erstellt hast.
1)
Beim Worker class hast du wie folgende implementiert:Worker::Worker(QObject *parent) : QObject(parent) { } void Worker::init() { timer = new QTimer(this); timer->setInterval(100); connect(timer, &QTimer::timeout, this, &Worker::calculate); }
Hier habe ich eine Frage im bezug auf das :
connect(timer, &QTimer::timeout, this, &Worker::calculate);
Hier tust folgende:
wird eine timeout (Signal) auftreten, dann wird das Slot calculate aufgerufen.
Richtig?
dann die restlichen Implemtierung
...void Worker::calculate() { qreal result = qPow(m_Base, m_Expo); emit qThreadResult(QString::number(result) + " um "+QTime::currentTime().toString("mm:hh:ss.zzz")); } // einfach signal "qThreadResult(...)" emittiert
2)
Bei deinem class MainWindow in der Konstruktor hast du folgende geschrieben:MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ..... //!QThread //Initalisierung des Threads und der Workerklasse QThread * workerThread = new QThread(); Worker *workerObject = new Worker(); workerObject->moveToThread(workerThread); connect(workerThread, &QThread::started, workerObject, &Worker::init); //QThread und Worker aufräumen bei Programmende connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); connect(workerThread, &QThread::finished, workerObject, &Worker::deleteLater); connect(qApp, &QApplication::aboutToQuit, workerThread, &QThread::quit); // Interaktion mit der Benutzeroberfläche connect(ui->btnQThread, &QPushButton::clicked, workerObject, &Worker::start); connect(workerObject, &Worker::qThreadResult, ui->lblResult,&QLabel::setText); connect(ui->dSpinBase, QOverload<double>::of(&QDoubleSpinBox::valueChanged), workerObject, &Worker::newBase); connect(ui->dSpinExp, QOverload<double>::of(&QDoubleSpinBox::valueChanged), workerObject, &Worker::newExponent); workerThread->start(); }
Mich interessiert das:
connect(workerThread, &QThread::started, workerObject, &Worker::init); // hier baut eine Verbindung zwischen das Signal started von QThread Object und das Slot von Worker Object //also solange der QThread noch lebt wird immer der slot init aufgerufen, der wiederum das Slot calculate aufruft.
Richtig?
10000 danke in voraus und Sorry
-
Guten Morgen @Galilio ,
zu deinem letzten post:
das Signal
QThread::started
wird nur dann ausgelöst wenn QThread bereit ist die EventLoop zu starten, also kurz bevor (intern)exec
inrun
gecalled wird.Das passiert eigendlich nur einmal in der Lebenszeit des Threads.
Ist nen Privates Signal, d.h. nur das QThread Object kann es auslösen, aber man kann sich von außerhalb an das Signal hängen, mit nem
connect
. Klick hier zum nachlesenUnd das ist auch was im Beispiel passiert. Weil
connect(workerThread, &QThread::started, workerObject, &Worker::init);
eine Qt::Queuedconnection ist, wird init auf jedenfall erst dann ausgeführt, wenn die QThread eventloop läuft.Der Connecttyp ist nicht expliciet definiert -> Auto als standart -> Queuedconnection weil Threadübergreifend.
Zu dem post davor,
sieht so aus, als ob die Objecte im Constructor im original Thread erstellst und nicht mit verschiebst. Aber ohne Code ist da schwer was zu sagen, der Stacktrace sollte dir aufschluß darüber geben in welcher Zeile das passiert. Programm mal in Debug starten und gucken :-) -
Problem tritt wenn die Application verlassen wird.
Beim Verlassen der application wird der destrctor der CAgilentLan aufgerufen, der so aussieht:
CAgilentLan::~CAgilentLan() { this->Close(GetiTimeOutClose()); if (this->Execute("DeleteObject", 0, 0, 0) != enRspOK) { throw(QString("Error AgilentLan.CPP/Destructor TcpSocket Delete memory error")); } }
die close Methode sieht wie folgende aus:
bool CAgilentLan::Close(const int iTimeout_p) { bool boRet_l = true; if (this->Execute("CloseConnection", 500, iTimeout_p, 1000) != enRspOK) { throw(QString("Error AgilentLan.CPP/Close Connection error")); } if (GetboDebug()) { throw(QString("Tcp Socket is closed")); } return boRet_l; }
und genau gesagt hier knallt:
GetTcpSocket()->disconnectFromHost();
Das Object "GetTcpSocket()" ist nicht gleich NULL, sonst hätte ich einen ganze andere Fehlermeldung.
-
Guten morgen zusammen
Problem wurde gelöst.
ich habe es immer den falschen Thread benutzt und dazu versuche ich ihm zu löschen.
danke
@J-Hilk -
This post is deleted! -
@Galilio
hi,Warum bestehst du eigentlich auf einer Synchronen TCPSocket Lösung? Wenn möglich sollte man immer die Asynchronen Funktionen nehmen.
Das gesagt,
waitForDisconnected
hat in der docu den BeisatzNote: This function may fail randomly on Windows. Consider using the event loop and the disconnected() signal if your software will run on Windows.
Also besondere Vorsicht die man hier walten lassen sollte.
if ((GetTcpSocket()->state() == QAbstractSocket::UnconnectedState) || (GetTcpSocket()->waitForDisconnected(GetTimeOut())))
ist an sich nicht falsch, der erste Parameter wird immer zuerst geprüft, und falls true, wird der Rest des IF-Statements ignoriert.
Ist aber trotzdem eine blockierende Funktion und wird deinen Thread für bis zu 3 Sekunden, der default timeout, freezen.Ich würde es etwas anders lösen, und zwar über das Signal
stateChanged
vom TcpSocketconnect(tcpSocket, &QTcpSocket::stateChanged, this, [=](QAbstractSocket::SocketState socketState{ if(socketState == ConnectedState) emit SocketConnected(); if(socketState == UnconnectedState) emit SocketDisconnected(); });
einen Timeout kannst du dir ganz leicht selbst machen mit einem QTimer
void disconnectMySocket(){ tcpSocket->disconnectFromHost(); QTimer::singleShot(3000, this, &mySocketClass::checkDisconnected); } void checkDisconnected(){ if(tcpSocket->state != UnconnectedState){ //Error Handling } }
-
@J.Hilk
vielen dank
Dein tipps sind super -
@J.Hilk
Hi,Das
void disconnectMySocket(){ tcpSocket->disconnectFromHost(); QTimer::singleShot(3000, this, &mySocketClass::checkDisconnected); } void checkDisconnected(){ // Diese Funktion wird aber ne aufgerufen if(tcpSocket->state != UnconnectedState){ //Error Handling } }
wird aber ne erreicht.
-
@Galilio
mit ziehmlicher sicherheit wird das aufgerufen x), Fehlermeldungen falls vorhanden immer mit posten.Ich hab das so vereinfacht geschrieben wie möglich, das muss an dein Programm angepasst werden.
wenn die den Slot vermeiden möchtest kann man das auch in ein Lamda stecken.
Das wird auf jeden Fall aufgerufen, oder zumindest wird der compiler abbrechen mit einer Fehlermeldung:void disconnectMySocket(){ tcpSocket->disconnectFromHost(); QTimer::singleShot(3000, this, [=]{ if(tcpSocket->state != UnconnectedState){ //Error Handling } }); }
-
@J.Hilk
aber wenn ich so schreibe :void disconnectMySocket(){ tcpSocket->disconnectFromHost(); QTimer::singleShot(3000, this, [=]{ qDebug() << "checkDisonnected"; if(tcpSocket->state() != UnconnectedState){ //Error Handling } }); }
dann muss er rein aber der tut es nicht.
Hier wird der SocketConnect bzw. SocketDisconnected emitted und das entsprechende Slot aufgerufen
connect(GetTcpSocket(), &QTcpSocket::stateChanged, this, [=](QAbstractSocket::SocketState socketState) { if (socketState == QAbstractSocket::ConnectedState) { qDebug() << "Connected"; emit SocketConnected(); } if (socketState == QAbstractSocket::UnconnectedState) { qDebug() << "Disconnected"; emit SocketDisconnected(); } });
-
@Galilio said in QThread richtig einsetzen?:
disconnectMySocket()
setze mal einen Breakpoint oder eine qDebug() line um zu schaun, ob
disconnectMySocket()
überhaupt aufgerufen wird. -
Das habe ich gemacht.
disconnectMySocket()
Dieses wird schon aufgerufen, aber
checkDisconnected()
wird ne aufgerufen.
-
@Galilio mmh
#include <QTimer>
ist gemacht? Clean Build durchgeführt? Eventuell ShadowBuild-Ordner löschen. -
@J.Hilk said in QThread richtig einsetzen?:
@Galilio mmh
#include <QTimer>
ist gemacht? Clean Build durchgeführt? Eventuell ShadowBuild-Ordner löschen.
habe ich gemacht