If I have a class FunctionsClass that inherits QObject and has a QTcpServer and QTcpClient in it as member variables. In my main UI class I set up the FunctionsClass member variable on a Qthread called FunctionClassThread by doing:
FunctionsClass *classObj = new FunctionsClass // (classObj is a class member)
classObj->moveToThread( &FunctionClassThread );
FunctionClassThread.start();
// connected some signal/slots..
// do some stuff...
Then I deconstruct the object containing my instance of FunctionsClass by doing:
FunctionClassThread.quit();
FunctionClassThread.wait();
delete classObj; // problem line...........
This error only happens when classObj's QTcpServer is currently listening or itsQTcpSocket is attempting to connect to a server and I delete classObj. The error is: ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread.
Any ideas?
After moving classObj to another thread, you can no longer delete it from the thread you created it in. You either have to delete it within your FunctionsClassThread or move it back to the main thread via code which is processed within the FunctionsClassThread.
Read the Qt docs on moveToThread():
This function can only "push" an object from the current thread to
another thread, it cannot "pull" an object from any arbitrary thread
to the current thread.
So just before your FunctionsClassThread is about to stop, it has to call
classObj->moveToThread( QApplication::thread() );
Of course your FunctionsClassThread needs to be aware of the object, either directly, or by using signals & slots
A QObject has thread affinity. It only likes to be manipulated from the thread it was created in . Use QMetaObject::invokeMethod to invoke a method in context of another thread
Related
I have a slot in class B which will connect to signal in class A, but class B will be deconstructed inconstantly, so during class B's deconstruction, should I disconnect the slot or will it be disconnected by QT? If I should manually disconnect the connection, how can I do it?
Qt takes care of disconnection. You don't have to worry about it.
But it's recommended to use
obj->deleteLater();
method rather than
delete obj;
Same Question Exists
You can catch the signal void QObject::destroyed(QObject * obj = 0) to do some clean-up:
This signal is emitted immediately before the object obj is
destroyed, and can not be blocked.
All the objects's children are destroyed immediately after this signal
is emitted.
To answer:
should I disconnect the slot or will it be disconnected by QT? If I
should manually disconnect the connection, how can I do it?
A signal-slot connection is removed when either of the objects involved are destroyed.
If you are not using thread you can disconnected another class slot like below code here:
You will call within constructor of A class not outside of constructor
bttnShutdown = new QPushButton(this);
bttnShutdown->setGeometry(290, 2, 25, 26);
myWorker =new B;
connect(bttnShutdown, SIGNAL(clicked()), myWorker, SLOT(dowork()));
I have Qt application, with some external library dependencies. My application and external libraries does not use threads (seems to me). There is no thread word in sources of them. One library have derivative from QTcpServer with no listen() method overloading. (OS is windows)
I create an object and call listen() method in the constructor of Window class. The warning message at console appears during listen() method call:
QObject: Cannot create children for a parent that is in a different
thread. (Parent is QJsonRpcTcpServer(0x4c1b38), parent's thread is
QThread(0x4a8d98), current thread is QThread(0x47e348)
The Qt subsystem and so on create additional threads, one of them UI thread etc. Some mesh or intersection exists or something else. After that program is not worked properly. (tcp client connect and lies until program is not closed)
What is the possible vector to debug problem?
Window::Window( QWidget *parent ) {
Service* service = new Service( parent );
QJsonRpcTcpServer* rpcServer = new QJsonRpcTcpServer( parent );
rpcServer->addService(service);
// problem at next line:
if ( rpcServer->listen(QHostAddress::Any, 42123) ) {
}
}
Some new info, when I replace QJsonRpcTcpServer with QTcpServer then warning at listen() call is disappear.
Some more new info, the problem is on windows. Build and run at FreeBSD is ok - no errors and work as expected.
How can I deal with the debug message and the fact that the worker thread prevented to start? I am getting:
"Cannot create children for a parent that is in a different thread." message in debug output.
There several ways to dynamically allocate the object and still keep track of it in Qt without using QObject base with parent (owner) passed to it. For example QScopedPointer as a member of a class of that 'parent' object instead:
/// snip ///
#include <QScopedPointer>
class Service;
class QJsonRpcTcpServer;
class Window : public QWidget
{
/// snip ///
QScopedPointer<Service> m_service;
QScopedPointer<QJsonRpcTcpServer> m_rpcServer;
};
/// snip ///
Window::Window( QWidget *parent ) {
m_service.reset(new Service( nullptr )); // unsure of default
m_rpcServer.reset(new QJsonRpcTcpServer( nullptr )); // constructor, take nullptr
m_rpcServer->addService(m_service);
// was problem at next line: not anymore
if ( m_rpcServer->listen(QHostAddress::Any, 42123) ) {
}
}
I also suspect that QJsonRpcTcpServer::addService is taking responsibility of releasing 'service' object. But that I cannot prove with docs, so try to find an answer to it as well. Mind that QScopedPointer or std::unique_ptr will always work deterministic but QObject::destroyed signal doing deferred release via QObject::deletelater is more prone to 'surprises' starting from when exactly the object gets released.
This question already has answers here:
How delete and deleteLater works with regards to signals and slots in Qt?
(4 answers)
Closed 8 years ago.
When processing requests in my qt server application sometimes I have to wait for a "resource" to become free. De to my understanding sleeping in the slot implementation would stop the mesasge loop, so this probably won't work as expected:
void MyClass::mySlot(/*some params here*/)
{
while (resource.busy())
{
QThread::sleep(50);
if (timeout)
break;
}
if (!timeout)
doWork();
}
I thought of using QTimer e.g. with singleShot. My research shows, I cannot pass the parameters through the timer's signal.
My next approach would be to create an instance of a new object for each request, put the parameters to this request and use this object as recipient for the timer signal. In this slot I have to delete the request object because I haven't stored a reference to it (and don't want to).
void MyClass::mySlot(/*some params here*/)
{
Request* request;
request->setParams(...);
request->processRequest();
}
void Request::processRequest()
{
if (resource.busy())
{
// timeout missing in example/pseudocode
QTimer::singleShot(50, this, SLOT(processRequest()));
}
else
{
doWork();
delete this; // allowed by C++, but ugly. allowed by qt? better approach?
}
}
Is there a better approach for freeing the request object or even a better approach for my problem? If not: is it valid to use delete this; in this context?
You can use QObject::deleteLater(). From the documentation :
Schedules this object for deletion. The object will be deleted when
control returns to the event loop. If the event loop is not running
when this function is called (e.g. deleteLater() is called on an
object before QCoreApplication::exec()), the object will be deleted
once the event loop is started. If deleteLater() is called after the
main event loop has stopped, the object will not be deleted. Since Qt
4.8, if deleteLater() is called on an object that lives in a thread with no running event loop, the object will be destroyed when the
thread finishes. Note that entering and leaving a new event loop
(e.g., by opening a modal dialog) will not perform the deferred
deletion; for the object to be deleted, the control must return to the
event loop from which deleteLater() was called.
I am new to Qt and trying to learn the Qt threading mechanism. I am in a situation where I would like a background thread to perform some long running task and report the results to another (or main) thread after processing every 100 items. Right now I am doing this by emitting a signal from the background thread containing a list of the processed objects that is received in a slot in the main thread. Does Qt make a copy of the signal argument when it is received in the slot ? If so, how does how does calling qRegisterMetaType help with that ? This is what I am tying to accomplish in my code :
//background thread
void run(){
//get a query object from database
int fireCount = 0;
QList< QList<QVariant> > data;
while(query->next()){
fireCount++;
QList<QVariant> row;
//do some calculations on the fields read from the query
processRow(query,&row);
data.append(row);
if(fireCount>100){
emit publishDataToMainThread(data);
fireCount = 0;
data.clear();
}
}
}
//slot in main thread
void receiveData(QList< QList<Qvariant> > data){
\\display the data
}
Also , is this a recommended practice for transferring objects between threads ?
This is a perfectly fine way of doing it. QList uses implicit sharing (i.e. copy on write) so copying it means copying one pointer and increasing the reference count. It only gets copied once you try to modify it.
Just remember to use Qt::QueuedConnection when connection the signal to the slot so that the slots gets run in the receivers thread.
qRegisterMetaType or Q_DECLARE_METATYPE are needed so that you can pass parameters by value in signals. It tells the Qt Metatype system (which is sort of like reflection) that this type exists.
I have an app with such structure: all the datatypes (class INode) are stored in plugins (DLLs). Some of the datatypes can be drawn (if they're IDrawable).
To load an object of, e.g. class PointCloudNode: public INode I have a special input plugin (DLL) which is called class PointCloudParser: public IIOPlugin and IIOPlugin is a thread with some specific functionality: class IIOPlugin: public QThread.
All the objects are created by NodeFactory class which is a singleton stored in separate DLL.
And here's the problem:
void PointCloudNode::update()
{
QObject::connect (this,SIGNAL(tmptmp()),this,SLOT(drawObject()));
emit tmptmp();
}
If I do this from any thread (main thread or the Input Plugin thread)
NodeFactory* fab = NodeFactory::getInstance();
boost::shared_ptr<INode> pc(fab->createNode("pointCloud","myPC"));
boost::shared_ptr<IDrawable> dr = boost::dynamic_pointer_cast<IDrawable>(pc);
dr->update();
The update launches, the tmptmp() signal is emitted, and the slot (drawObject()) executes correctly.
BUT
if do just the same, but create the object in my Input Plugin, pass over the shared pointer and execute dr->update() in another function, the slot drawObject() is never entered though all the code is executed (including connect, etc.).
To be more precise, here's the Input Plugin:
void PointCloudParserPlugin::doLoad(const QString& inputName, boost::shared_ptr<INode> container)
{
NodeFactory* factory = NodeFactory::getInstance();
boost::shared_ptr<INode> node = factory->createNode("pointCloud", inputName);
// here goes the loading itself, nothing special...
container->addChild(node); //that's the container where I keep all the objects
//boost::dynamic_pointer_cast<IDrawable>(container->getChild(inputName))->update();
//If I uncomment this line, it all works: the slot is launched.
emit loadingFinished(inputName); // it executes the following function
}
The last emit is connected to this:
void GeomBox::updateVisualization(const QString& fileName)
{
boost::shared_ptr<INode> node = container_->getChild(fileName);
boost::shared_ptr<IDrawable> nodeDrawable = boost::dynamic_pointer_cast<IDrawable>(node);
nodeDrawable->update(); //this is the problem line: update() executes, connect() works, but the slot never runs :(
}
How come? The node object is the same all the way through, it is valid. Every line in code in launched, QObject::connect doesn't write anything to debug window, the signal tmptmp() is emitted, but the slot drawObject() in one case is never reached? Any ideas?
Upd.: If I do not inherit IIOPlugin from QThread, everything works fine (i.e. load the object in the main thread). I expected the signals/slots to work across the threads...
Since you are sending a signal across to a different thread, you might need to explicitly tell Qt that the connection should be a queued one:
QObject::connect(this, SIGNAL(tmptmp()), this, SLOT(drawObject()), Qt::QueuedConnection );
By default Qt will use Qt::AutoConnection as that last parameter, and it will choose whether to use a direct connection (if the slot is in the same thread as the emitter) or a queued connection (if the slot is in a different thread). But since your thread is in a separate library, maybe Qt isn't making the right assumption here.