Communicating with QProcess from a QThread - c++

Structure Of Application:
MainWindow -> ProcessingThread(QThread) - > QProcess for Python Script
In the Run/Exec loop of Processing Thread I would like to interact with the process.
How do I go about it?
Current Problem:
I know both ProcessingThread(QThread) and its Run loop run inside different threads. Hence if I initialize the QProcess in QThread constructor I am unable to interact with the process because of following error:
QSocketNotifier: Socket Notifiers cannot be enabled or disabled from
another thread
and if I try to initialize the process in the Run Loop I get the following error:
QObject: Cannot create children for a parent that is in a different
thread
(Parent is ProcessingThread(0x984b2a0), parent's thread is QThread(0x940e180)),
current thread is ProcessingThread(0x984b2a0)
If I initialize the QProcess in ProcessingThread constructor, I am able to interact with the script perfectly.
Any suggestions?
Update: Also The reason for using QThread is because I am performing image processing, the Processing Threads keeps fetching images from camera. Some of these images need to be further processed by the Python script running in QProcess.
Update 2: CODE
void MainWindow::MainWindow(QWidget *parent)
{
...
debugProcessingThread = new DebugProcessingThread();
}
class DebugProcessingThread : public QThread
{
Q_OBJECT
...
private:
qProcess *myprocess;
}
DebugProcessingThread::DebugProcessingThread()
{
...
myProcess = new QProcess(this);
myProcess->start("python abc.py");
connect(myProcess, SIGNAL(started()), this, SLOT(processStarted()));
connect(myProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError()));
connect(myProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));
myProcess->waitForStarted();
}
void DebugProcessingThread::processError()
{
qDebug("PROCESS ERROR");
qDebug() << myProcess->errorString();
}
void DebugProcessingThread::readStandardOutput()
{
qDebug("READ DATA");
qDebug(myProcess->readAll().toStdString().c_str());
myProcess->write("out.txt\n");
}
void DebugProcessingThread::processStarted()
{
qDebug("Process has started");
}
The above code works perfectly.
But I want to send and receive data from function:
void DebugProcessingThread::run()
{
myProcess->write("out.txt\n");
// This Throws socket Error
}

Keep long story short, you shouldn't instantiate anything you going to use in your new thread in the constructor, as every object instantiated there will get an affinity of the thread where your QThread object is created, common practice is either not to subclass QThread at all, just use QObject and moveToThread, and then connect some slot like init() to QThread started() signal, so you can do all initialisation inside the init() which will run inside a new thread, or if for whatever reasons you need QThread subclassing instantiate everything in run().
Also pay attention that QThread itself is nothing more nothing less then a wrapper of your real thread and stays as an object in a thread where you created it.

Related

QLabel not updating image content [duplicate]

I work in Qt and when I press the button GO I need to continuously send packages to the network and modify the interface with the information I receive.
The problem is that I have a while(1) in the button so the button never finishes so the interface is never updated. I thought to create a thread in the button and put the while(){} code there.
My question is how can I modify the interface from the thread? (For example how can I modify a textBox from the thread ?
Important thing about Qt is that you must work with Qt GUI only from GUI thread, that is main thread.
That's why the proper way to do this is to notify main thread from worker, and the code in main thread will actually update text box, progress bar or something else.
The best way to do this, I think, is use QThread instead of posix thread, and use Qt signals for communicating between threads. This will be your worker, a replacer of thread_func:
class WorkerThread : public QThread {
void run() {
while(1) {
// ... hard work
// Now want to notify main thread:
emit progressChanged("Some info");
}
}
// Define signal:
signals:
void progressChanged(QString info);
};
In your widget, define a slot with same prototype as signal in .h:
class MyWidget : public QWidget {
// Your gui code
// Define slot:
public slots:
void onProgressChanged(QString info);
};
In .cpp implement this function:
void MyWidget::onProgressChanged(QString info) {
// Processing code
textBox->setText("Latest info: " + info);
}
Now in that place where you want to spawn a thread (on button click):
void MyWidget::startWorkInAThread() {
// Create an instance of your woker
WorkerThread *workerThread = new WorkerThread;
// Connect our signal and slot
connect(workerThread, SIGNAL(progressChanged(QString)),
SLOT(onProgressChanged(QString)));
// Setup callback for cleanup when it finishes
connect(workerThread, SIGNAL(finished()),
workerThread, SLOT(deleteLater()));
// Run, Forest, run!
workerThread->start(); // This invokes WorkerThread::run in a new thread
}
After you connect signal and slot, emiting slot with emit progressChanged(...) in worker thread will send message to main thread and main thread will call the slot that is connected to that signal, onProgressChanged here.
P.s. I haven't tested the code yet so feel free to suggest an edit if I'm wrong somewhere
So the mechanism is that you cannot modify widgets from inside of a thread otherwise the application will crash with errors like:
QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
Segmentation fault
To get around this, you need to encapsulate the threaded work in a class, like:
class RunThread:public QThread{
Q_OBJECT
public:
void run();
signals:
void resultReady(QString Input);
};
Where run() contains all the work you want to do.
In your parent class you will have a calling function generating data and a QT widget updating function:
class DevTab:public QWidget{
public:
void ThreadedRunCommand();
void DisplayData(QString Input);
...
}
Then to call into the thread you'll connect some slots, this
void DevTab::ThreadedRunCommand(){
RunThread *workerThread = new RunThread();
connect(workerThread, &RunThread::resultReady, this, &DevTab::UpdateScreen);
connect(workerThread, &RunThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
The connection function takes 4 parameters, parameter 1 is cause class, parameter 2 is signal within that class. Parameter 3 is class of callback function, parameter 4 is callback function within the class.
Then you'd have a function in your child thread to generate data:
void RunThread::run(){
QString Output="Hello world";
while(1){
emit resultReady(Output);
sleep(5);
}
}
Then you'd have a callback in your parent function to update the widget:
void DevTab::UpdateScreen(QString Input){
DevTab::OutputLogs->append(Input);
}
Then when you run it, the widget in the parent will update each time the emit macro is called in the thread. If the connect functions are configured properly, it will automatically take the parameter emitted, and stash it into the input parameter of your callback function.
How this works:
We initialise the class
We setup the slots to handle what happens with the thread finishes and what to do with the "returned" aka emitted data because we can't return data from a thread in the usual way
we then we run the thread with a ->start() call (which is hard coded into QThread), and QT looks for the hard coded name .run() memberfunction in the class
Each time the emit resultReady macro is called in the child thread, it's stashed the QString data into some shared data area stuck in limbo between threads
QT detects that resultReady has triggered and it signals your function, UpdateScreen(QString ) to accept the QString emitted from run() as an actual function parameter in the parent thread.
This repeats every time the emit keyword is triggered.
Essentially the connect() functions are an interface between the child and parent threads so that data can travel back and forth.
Note: resultReady() does not need to be defined. Think of it as like a macro existing within QT internals.
you can use invokeMethod() or Signals and slots mechanism ,Basically there are lot of examples like how to emit a signal and how to receive that in a SLOT .But ,InvokeMethod seems interesting .
Below is example ,where it shows How to change the text of a label from a thread:
//file1.cpp
QObject *obj = NULL; //global
QLabel *label = new QLabel("test");
obj = label; //Keep this as global and assign this once in constructor.
Next in your WorkerThread you can do as below:
//file2.cpp (ie.,thread)
extern QObject *obj;
void workerThread::run()
{
for(int i = 0; i<10 ;i++
{
QMetaObject::invokeMethod(obj, "setText",
Q_ARG(QString,QString::number(i)));
}
emit finished();
}
you start thread passing some pointer to thread function (in posix the thread function have the signature void* (thread_func)(void*), something equal under windows too) - and you are completely free to send the pointer to your own data (struct or something) and use this from the thread function (casting pointer to proper type). well, memory management should be though out (so you neither leak memory nor use already freed memory from the thread), but this is a different issue

QT QThread::isrunning freeze program on Pi

I'm testing a programm on my PI.When running it on the host pc no error is shown, instead , running it on pi (CM3) it freezes.
I'm trying to use multithreading.
From the main thread, in the constructor an QThread is started, then when I click on the button to open a new form the GUI freezes. In the button slot I need to check if the serial_works thread has been started in the constructor has finished before opening a new form, so I added a QThread::isRunning() check;
Main_Form::Main_Form(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Main_Form)
{
ui->setupUi(this);
this->move(0,0);
this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
connect(ui->btn,SIGNAL(clicked(bool)),this,SLOT(open_form()));
*serial_works = new SerialWorks();
serial_works->start();
}
void Main_form::open_form(){
std::cout<<"open form slot"<<std::endl;
int i = 0;
while(serial_works->isRunning()){
std::cout<<"WHILE"<<std::endl;
QThread::msleep(100);
i++;
if(i > 10){
serial_works->terminate();
}
Next_form *frm = new Next_form();
this.close();
frm->show();
}
the run method in the Serial_works class is
void Serial_works::run() {
my_function();
this->terminate();
this->wait();
}
void Serial_works::my_function(){
....stuff on serial
std::cout<<"serial works finished"<<std::endl;
}
on the output i get
//serial works finished
//open_slot_form
no WHILE is printed out on the console,thus the program get stuck on the while check
serial_works->isRunning()
Where is the problem? On the the host pc, the new form opens as expected.
You are trying to use QThread without understanding what is this object doing. What you want to do is asynchronous execution : Do some work and when you are done let me know.
Edit : What is Happening :
Client : main thread executes open_form before the worker executes run
Rasberry Pi : worker executes run before main thread executes open_form
On PI
serial_works->start() launch worker, which execute first, and complete my_function.
worker call this->terminate() and is now officially dead. terminate is a brutal way of stopping a QThread..I cannot even speculate whether wait() is called.
The main thread execute open_form, and the worker is already non-runnable. So the loop is not executed and Next_form is never going to be shown.
Error 1 :
Main_form::open_form()
is executing in the gui thread, and you are sleeping on a event. This is always incorrect. You GUI will freeze for the amout of time you are sleeping. Use signals and slots or events.
Error 2 :
Serial_works is likely a subclass of Qthread. You are confusing a thread of execution with the object managing that thread. You should not subclass QThread.
this->terminate();
this->wait();
The worker thread is executing that code. You are killing yourself then waiting on your death. So depending on the implementation you may wait forever , crash, etc....
What you need to do :
Use QFuture and QFutureWatcher.
//inside Main_Form
QFutureWatcher<ReturnValueType> watcher;
void Main_form::open_form(){
// Instantiate the objects and connect to the finished signal.
connect(&this->watcher, SIGNAL(finished()), &this, SLOT(SignalWorkFinished()));
// Start the computation.
QFuture<ReturnValueType> future = QtConcurrent::run(stuffOnSerialFunction);
this->watcher.setFuture(future);
}
// now handle work finish
void SignalWorkFinished()
{
QFuture<ReturnValueType> future = watcher.future();
//do whatever you like
}

Qt threading, Crash from the destructor of the QObject moved

I'm trying to move a connection handler (containing a QTCPSocket object) to a separate thread from the QMainWindow object.
So far it works, but if I close the QMainWindow, It crashes and I receive the following:
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 1680d0. Receiver '' (of type 'QAbstractSocket') was created in thread 34fe0c"
Here is my code:
in the QMainWindow constructor (subclassed):
QThread m_commsThread;
m_pICommsHandler = new CommsHandlerIP();
m_pICommsHandler->moveToThread(&m_commsThread);
// when it starts, we start the connection
connect(&m_commsThread,SIGNAL(started()),m_pICommsHandler,SLOT(connectToHost()));
m_commsThread.start();
in the QMainWindow destructor:
m_commsThread.quit();
m_commsThread.wait();
delete m_pICommsHandler;
About CommsHandlerIP.cpp
CommsHandlerIP::CommsHandlerIP() {
m_TCPSocket = new QTcpSocket(this);
}
CommsHandlerIP::~CommsHandlerIP(void)
{
m_TCPSocket->deleteLater(); // It's going to crash a bit later if I have this line
}
m_TCPSocket should be in the right thread to be deleted but I feel like by closing the main thread, the affinity has become messy.
What should I do?
I think there might be two things happening:
As far as i remember, there were always some issues with Qt4 when calling moveToThread() on a QAbstractSocket.
When you call deleteLater() on your socket, the thread in which it lives is already stopped.
A possible solution could be to subclass your CommsHandlerIP from QThread and override run():
CommsHandlerIP::CommsHandlerIP() :
QThread(),
m_TCPSocket(0)
{
moveToThread(this);
}
void CommsHandlerIP::run()
{
m_TCPSocket = new QTcpSocket(this);
connectToHost();
exec();
m_TCPSocket->close();
delete m_TCPSocket;
}

QThread finished() emitting fails if called inside window closing

I have done an application with some threads. Everything seems to work ok if I call my stopConsumer inside a keypressedEvent. But If I call it inside a destructor of closeEvent.. it fails.
My QThread class that has a run method like this one:
void Consumer::run()
{
forever {
// do something something
// do something something
// do something something
//-------------------------------- check for abort
abortMutex.lock();
if(abort) {
abortMutex.unlock();
qDebug() << "abort..";
break;
} abortMutex.unlock();
//-------------------------------- check for abort
}
qDebug() << "Consumer > emit finished()";
emit finished();
}
void Consumer::stopConsume() {
abortMutex.lock();
abort = true;
abortMutex.unlock();
}
and a method in the MainWindow:
void initConsumers()
{
consumer1 = new Consumer(....);
connect(consumer1, SIGNAL(finished()),
this, SLOT(deleteConsumer()));
consumer1->start();
}
void stopConsumer() {
if(consumer1!=NULL) {
qDebug() << "stopConsumer";
consumer1->stopConsume();
}
}
If I have a keypressed that calls stopConsumer.. it's ok, deleteConsumer is reached.
If I call stopConsumer inside the MainWindow destructor or inside a MainWindow closeEvent.. the slot deleteConsumer is never reached!
Any ideas?
Given that the Consumer class and your MainWindow have different thread affinities, the call you make to connect inside initConsumers() is likely using a Qt::QueuedConnection, which means that the deleteConsumer() slot won't get called immediately.
If you would like to ensure that the consumer gets deleted from the destructor of your main window (or equivalently, from a close event), one possible solution is to call stopConsume() on the consumer, then wait until the thread is no longer running (see http://qt-project.org/doc/qt-5.1/qtcore/qthread.html#isRunning), then call deleteConsumer() directly.
Update
Here's an example of what I described above:
consumer1->stopConsume();
consumer1->wait();
deleteConsumer();
It's not advisable to switch the connection type to Qt:DirectConnection since that will cause the deleteConsumer() function to be called from the body of Consumer::run(), which will likely crash your application.
Part of the problem here is that you're deriving from QThread, which is not how it is supposed to be used. You can read about why deriving from QThread is wrong here.
Instead, what you should be doing is deriving your class from QObject, creating a QThread object and moving the derived QObject instance to that thread.
class Consumer : public QObject
{
...
signals:
void finished();
private slots:
void run();
}
QThread pThread = new QThread;
Consumer pObject = new Consumer;
// move the pObject to the thread
pObject->moveToThread(pThread);
You can then control the thread with signals and slots.
// assuming you've added a run slot function to the Consumer class
connect(pThread, SIGNAL(started()), pObject, SLOT(run()));
connect(pObject, SIGNAL(finished()), pThread, SLOT(quit()));
connect(pObject, SIGNAL(finished()), pObject, SLOT(deleteLater()));
// Note the thread cleans itself up here, but if the app is quitting,
// waiting on the thread to finish may be required instead
connect(pThread, SIGNAL(finished()), pThread, SLOT(deleteLater()));
And start the thread: -
pThread->start();
Used this way, it also enables multiple objects to be moved to a single new thread, rather than creating a new thread per object instance.

QObject: Cannot create children for a parent that is in a different thread

EDIT:
I tried doing what you guys told me in comments ... :
Citizen * c = new Citizen(this);
QThread thread;
c->moveToThread(&thread);
connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
thread.start();
This produces even more errors:
QThread: Destroyed while thread is still running
ASSERT failure in QThread::setTerminationEnabled(): "Current thread was not started with QThread.", file c:\ndk_buildrepos\qt-desktop\src\corelib\thread\qthread_win.cpp, line 542
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
QObject::killTimers: timers cannot be stopped from another thread
I am having problems with this error ... I'm stuck on this for 2 days already and can't get a solution.
Header:
class Citizen : public QThread
{
Q_OBJECT
QNetworkAccessManager * manager;
private slots:
void onReplyFinished(QNetworkReply* net_reply);
public:
Citizen(QObject * parent);
void run();
};
Implementation:
Citizen::Citizen(QObject * parent)
{
manager = new QNetworkAccessManager;
connect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onReplyFinished(QNetworkReply*)));
}
void Citizen::onReplyFinished(QNetworkReply* net_reply)
{
emit onFinished(net_reply);
}
void Citizen::run()
{
manager->get(QNetworkRequest(QUrl("http://google.com"));
QEventLoop eLoop;
connect(manager, SIGNAL( finished( QNetworkReply * ) ), &eLoop, SLOT(quit()));
eLoop.exec(QEventLoop::ExcludeUserInputEvents);
qDebug() << "loaded google!";
exec();
}
When manager->get() gets executed, I get the following error:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0xc996cf8), parent's thread is QThread(0xaba48d8), current thread is Citizen(0xca7ae08)
When eLoop.exec() gets executed:
QObject::startTimer: timers cannot be started from another thread
I start this thread in the following manner:
Citizen * c = new Citizen(this);
c->start();
Why does this happen? How to solve this?
QObject: Cannot create children for a parent that is in a different thread.
You get this because you are creating the QNetworkAccessmanager in the constructor of Citizen, which is being called in the "original" thread. When the Citizen object is moved to the new thread the QNetworkAccessmanager still has its thread affinity set to the original thread but in the run call it will attempt to create the QNetworkReply object ( and probably other objects aswell ) in the new thread. Which produces the warning above.
If you create the manager in the run slot(or at any point after the Citizen object is moved to the new thread) that will not happen.
However you still have some issues. For instance, the Citizen class really doesn't need to be a QThread. It needlessly complicates it. It will suffice for your purpose(afaict) to subclass a QObject. Just make a normal slot and connect that to the QThread::started() signal. And as OrcunC pointed out you need to make sure that the QThread instance is properly scoped.
For more on threading: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/
Example:
QThread *thread = new QThread;
thread->start();
Citizen *worker = new Citizen;
worker->moveToThread(thread);
//startWorking can be equivalent of the run function
//in your current implementation and this is where you should
//create the QNetworkAccessManager
QMetaObject::invokeMethod(worker,"startWorking");
I will just try to answer why you are seeing QThread: Destroyed while thread is still running error.
If you do this
void mtMethod () {
Citizen * c = new Citizen(this);
QThread thread;
c->moveToThread(&thread);
connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
thread.start();
}
The thread object will be destroyed when you exit the function but the thread that has been started is still running !. Qt is warning you that you should either stop the thread or create the thread object in a bigger scope. (i.e make it a member function of your class). Something like this :
class myClass
{
virtual ~myClass ();
QThread mythread;
};
myClass::~myClass
{
mythread.stop ();
}
void myClass::mtMethod () {
Citizen * c = new Citizen(this);
c->moveToThread(&mythread);
connect(&mythread, SIGNAL(started()), c, SLOT(ProcessActions()));
mythread.start();
}
I don't believe the new thread exists until run is called. So the constructor is a different thread than run(). What happens if you move the creation of the manager object from the constructor to run()? I imagine that will fix the first error, if not the timer error as well.
Also, I think many people are still building threads the way you are, but you might want to check out this.
You need to consider thread affinity. That error message is not lying or insane, it's telling you exactly what's wrong.
Your problems are mostly due to trying to subclass QThread. Even though the documentation recommends it, it is not the best way to use QThread. Please see this question and answer for more information and links.
I haven't figured out the startTimers error although it could be related to the first one. In any case, you should be able to fix the first error. I have run into this problem in Qt a few times and I find this to be the "best" way to work around it is to create an initialize function and a cleanUp function. All members of the class are pointers that are initialized to NULL until run is called. Note that "best" is in quotes because there are sure to be differing opinions but it works for most situations for me.
Header
class Citizen : public QThread {
Q_OBJECT
QNetworkAccessManager * manager;
private slots:
void onReplyFinished(QNetworkReply* net_reply);
public:
Citizen(QObject * parent);
void run();
private:
void initialize();
void cleanUp();
};
Implementation
Citizen::Citizen(QObject * parent) :
manager(NULL) {
}
void Citizen::onReplyFinished(QNetworkReply* net_reply) {
emit onFinished(net_reply);
}
void Citizen::run() {
initialize();
manager->get(QNetworkRequest(QUrl("http://google.com"));
QEventLoop eLoop;
connect(manager, SIGNAL( finished( QNetworkReply * ) ),
&eLoop, SLOT(quit()));
eLoop.exec(QEventLoop::ExcludeUserInputEvents);
qDebug() << "loaded google!";
exec();
cleanUp();
}
void Citizen::initialize() {
manager = new QNetworkAccessManager;
connect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onReplyFinished(QNetworkReply*)));
}
void Citizen::cleanUp() {
delete manager;
disconnect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onReplyFinished(QNetworkReply*)));
}