QProcess does not complete creating file - c++

I am just trying to create a file with QProcess by the following source code:
void Processmethod()
{
QDialog *ProcessMessage = new QDialog;
Ui::DialogProcessMessage Dialog;
Dialog.setupUi(ProcessMessage);
ProcessMessage->setModal(true);
ProcessMessage->setAttribute(Qt::WA_DeleteOnClose);
ProcessMessage->show();
processmethodONE();
}
void processmethodONE()
{
QString ProcessCommand = "w8 " + blablubli";
Prozess.setWorkingDirectory(Path); //QProcess "Prozess" is globaly defined
Prozess.setStandardOutputFile(Path); //in my class
Prozess.start(ProcessCommand);
QProcess::ExitStatus Status = Prozess.exitStatus();
if (Status == 0)
{
std::cout << "File created!" << std::endl;
}
}
This process creates out of another file which is located in the QString "Path" a new file, let me call it "PROFILE" (PRO for Problem :). The Profile also is created, but is never completed, I guess not even 50% of the file are completed.
Just when using
while(!Prozess.waitForFinished())
{
qApp->processEvents();
std::cerr << "Process Create PROFile running " << std::endl;
}
the file is written completely.
Furthermore I tried to use the QProcess finished(int) Signal to start another method and deleted the while loop (which freezes the whole GUI). I declared it in the constructor with:
connect(&Prozess, SIGNAL(finished(int)), this, (SLOT(processmethodTWO())));
But I guess this could not work because the first process isn't finished completely. Where is the problem?

There is no warranty that right after Prozess.start(ProcessCommand); process will be finished, so calling "Prozess.exitStatus();" right after it will give you "false positive". You certainly will have to wait until process is finished. You may either do it with with while loop, that you suggested or with QEventLoop
// ...
Prozess.setStandardOutputFile(Path); //in my class
QEventLoop loop;
connect(&Prozess, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
connect(&Prozess, SIGNAL(finished(int, QProcess::ExitStatus)), &loop, SLOT(quit()));
Prozess.start();
loop.exec();
// Now your process status should be valid:
QProcess::ExitStatus Status = Prozess.exitStatus();

Related

Why can't I start a QThread on a signal?

I want to start a QThread when another one starts, but it doesn't work.
main.cpp snippet
Worker stat_worker;
stat_worker.moveToThread(stat_worker.stat_thread);
Worker some;
some.moveToThread(some.somethread);
QObject::connect(stat_worker.stat_thread, SIGNAL(started()), some.somethread, SLOT(start()));
QObject::connect(some.somethread, SIGNAL(started()), &some, SLOT(print_some()));
stat_worker.stat_thread->start();
worker.h
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker();
QThread *stat_thread = new QThread;
QThread *somethread = new QThread;
signals:
//some signals
void start_thread();
public slots:
//some slots
void print_some();
void somethread_starter();
};
#endif // WORKER_H
worker.cpp related function
void Worker::print_some()
{
qInfo() << "-somethread started() signal arrived!";
}
When I tried starting a thread with clicking a pushbutton it didn't work either.
Even creating a slot which starts the thread:
QObject::connect(stat_worker.stat_thread, &QThread::started, &some, &Worker::somethread_starter);
void Worker::somethread_starter()
{
qInfo() << "-I got started by another thread!";
somethread->start();
}
or a signal that is emitted on starting the other thread:
void Worker::wip_status(){
emit start_thread();
}
QObject::connect(stat_worker.stat_thread, &QThread::started, &stat_worker, &Worker::wip_status);
QObject::connect(&stat_worker, &Worker::start_thread, &some, &Worker::somethread_starter);
work.
Thanks in advance for replying to my post.
I tried to reproduce OPs issue with my own MCVE (which is just a bit shorter).
#include <QtWidgets>
struct Worker: QObject {
QString name;
QThread qThread;
Worker(const QString &name): name(name)
{
moveToThread(&qThread);
connect(&qThread, &QThread::finished, this, &Worker::reportFinished);
}
void start()
{
qDebug() << "Start" << name;
qThread.start();
}
void reportFinished()
{
qDebug() << "Exit" << name;
}
};
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QCoreApplication app(argc, argv);
Worker worker1("worker 1");
Worker worker2("worker 2");
// install signal handlers
QObject::connect(&worker1.qThread, &QThread::started, &worker2, &Worker::start);
worker1.start();
// runtime loop
return app.exec();
}
Output:
Qt Version: 5.13.0
Start "worker 1"
This what OP observed. So, what?
the worker1.qThread.started signal is connected to the worker2.start slot
the worker1 is started
worker2 doesn't seem to start.
What made me suspicious: moveToThread().
The intention is to associate the Worker object with its member QThread.
What I'm not sure about: Is this possible before the QThread is started?
To check this out, I commented the moveToThread():
Worker(const QString &name): name(name)
{
//moveToThread(&qThread);
connect(&qThread, &QThread::finished, this, &Worker::reportFinished);
}
Output:
Qt Version: 5.13.0
Start "worker 1"
Start "worker 2"
The reason why I commented the moveToThread():
The call of qThread::start() should happen in the context of the main application (thread).
So, moving worker2 to its QThread means that the signal is sent to the event loop of worker2.qThread – which is actually not yet started.
Hence, the event cannot be processed.
The moveToThread() should be done later – e.g. in reaction of the started() signal:
#include <QtWidgets>
struct Worker: QObject {
QString name;
QThread qThread;
Worker(const QString &name): name(name)
{
connect(&qThread, &QThread::started, this, &Worker::moveThisToThread);
connect(&qThread, &QThread::finished, this, &Worker::reportFinished);
}
void start()
{
qDebug() << "Start" << name;
qThread.start();
}
void moveThisToThread()
{
moveToThread(&qThread);
qDebug() << name << "associated to its thread, from now.";
}
void reportFinished()
{
qDebug() << "Exit" << name;
}
};
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QCoreApplication app(argc, argv);
Worker worker1("worker 1");
Worker worker2("worker 2");
// install signal handlers
QObject::connect(&worker1.qThread, &QThread::started, &worker2, &Worker::start);
worker1.start();
// runtime loop
return app.exec();
}
Output:
Qt Version: 5.13.0
Start "worker 1"
"worker 1" associated to its thread, from now.
Start "worker 2"
"worker 2" associated to its thread, from now.
Bonus Question:
So does that mean "QThread::start" is useless as receiver of a signal?
No, it's not. Even if there is no existing signal with that signature (I know about) the application developer is free to “invent” one.
However, remembering that Qt5 doesn't actually require explicitly marked SLOTs to use them for signals, a more obvious answer may be found in the past:
With Qt4 signals, the QThread::start slot could have been connected to the QThread::started signal directly. (The default value of the one and only parameter in QThread::start becomes effective then.)
As I have no experience with Qt4 signals (I started with Qt5), I modified my sample code to prove me right:
QObject::connect(&worker1.qThread, SIGNAL(started()), &worker2.qThread, SLOT(start()));
Output:
Qt Version: 5.13.0
Start "worker 1"
"worker 1" associated to its thread, from now.
"worker 2" associated to its thread, from now.
The Start "worker 2" isn't emitted anymore as worker1.started() calls worker2.qThread.start() directly, now.
So, with Qt4 signals the original code of OP might have been worked.
It wasn't the incompatibility of signal and slot (as somebody guessed) which caused the issue but probably the above described moveToThread() issue (as well) which didn't make it work satisfyingly.

Connect signal of superclass of object

I am working with a QProcess and have connected QProcess's signal readyReadStandardOutput().
That process normally spits out data to the console regularly, but the readyReadStandardOutput() seems to batch results and only emit every half a minute or so (with all accumulated data).
I want to access the "live feed" of the QProcess so I thought maybe QProcess's superclass QIODevice has some other signals.
Other solutions instead of using bytesWritten are also welcome
Now I'm trying to connect bytesWritten, but it doesn't let me.
Code:
void MainWindow::on_Program_clicked() {
program= new QProcess(this);
QString file = "../folder/program/program.exe";
QString directory = "../folder/program/";
//qint64 pid;
program->setWorkingDirectory(directory);
program->start(file, {""});
program->waitForStarted();
connect(program, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput()));
//ERROR: "QObject::connect: No such signal QProcess::bytesWritten() in ..\---\mainwindow.cpp:45
connect(program, SIGNAL(bytesWritten()), this, SLOT(myBytesWritten()));
}
void MainWindow::myBytesWritten() {
QProcess *program = dynamic_cast<QProcess *>(sender());
QByteArray outData = program->readAll();
qDebug() << "DEBUG: " + outData;
}
//Works, but only emits a signal every so often, and not every time a new line is written to the console as when I launch the exe normally
void MainWindow::readOutput(){
QProcess *program = dynamic_cast<QProcess *>(sender());
QByteArray outData = program->readAll();
qDebug() << "DEBUG: " + outData;
}
If you want to use the old, deprecated way of connecting signals to slots, you need to also include the parameter list:
connect(program, SIGNAL(bytesWritten(int)), this, SLOT(myBytesWritten()));
Or you can just use the modern, compile-time Qt5 way:
connect(program, &QProcess::bytesWritten, this, &MainWindow::myBytesWritten);
Also note that bytesWritten fires when a write command from YOUR end has succeeded. You don't seem to be sending any input so this will never fire.

Qt Concurrent with signals & slots

I'm a novice in threads and someone advises me to use Qt Concurrent (Qt C++).
I'm trying to run a function in a thread by using Qt Concurrent, my functions runs well but my signal/slot is never emitted.
However for your information if I launch my function without using thread everything works fine.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QFutureWatcher<void> *watcher1 = new QFutureWatcher<void>();
connect(watcher1, SIGNAL(finished()), this, SLOT(getSizeFinished()));
QString string = "http://ipv4.download.thinkbroadband.com/50MB.zip";
QFuture<void> future1 = QtConcurrent::run(this, &MainWindow::getRemoteFileSize, string);
watcher1->setFuture(future1);
}
void MainWindow::getSizeFinished()
{
qDebug() << "--- FINISHED ---";
}
void MainWindow::getRemoteFileSize(const QString &url)
{
qDebug() << "Function - getRemoteFileSize";
QNetworkRequest req;
m_netmanager = new QNetworkAccessManager();
req.setUrl(QUrl(url));
m_reply = m_netmanager->get(req);
connect(m_reply, SIGNAL(metaDataChanged()), this, SLOT(remoteHTTPHeader()));
}
void MainWindow::remoteHTTPHeader()
{
qDebug() << "Function - remoteHTTPHeader";
remoteSize = m_reply->header(QNetworkRequest::ContentLengthHeader).toInt();
qDebug() << "Remote File Size: " << remoteSize;
m_reply->deleteLater();
m_netmanager->deleteLater();
qDebug() << "SIZE " << remoteSize;
}
You probably don't need to create a connection in this case, you could call MainWindow::remoteHTTPHeader() right after m_reply = m_netmanager->get(req);.
You might want to check if the reply is effectively finished like so:
if (m_reply->isFinished()) {
remoteHTTPHeader();
} else {
connect(m_reply, &QNetworkReply::finished, this, &MainWindow::remoteHTTPHeader);
}
This way you handle both fast and slow connections. Also notice how I created the connection using function pointers instead of SIGNAL and SLOT macro, this syntax is better since it checks at compile time if the functions exist so you avoid making typos and the like.

QNetworkAccessManager threads never finish

I know that in version 4.8 each http request gets its own thread to run.
I'm doing a links checker app that does a lot of http requests in a while loop and I notice in the windows task manager that my app is using more than 1600 threads over time and the number never goes down, only up until it crashes the app. (I'm guessing that is the cause.)
My question is, does QNetworkAccessManager have an option to use thread pool?
Or does it have an option to clean its threads after it finishes its http request?
This is the main loop:
while(!rpm_urlStack->isEmpty())
{
QString url = rpm_urlStack->top();
//define the reply
QNetworkReply *reply;
rpm_urlStack->pop();
QString urlForReq(url);
bool returnVal = true;
QNetworkRequest request;
request.setUrl(QUrl(urlForReq));
request.setRawHeader("User-Agent", USER_AGENT.toUtf8());
request.setRawHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
request.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
request.setRawHeader("Accept-Language", "en-us,en;q=0.5");
request.setRawHeader("Connection", "Keep-Alive");
QEventLoop loop;
reply = m_networkManager->get(request);
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exit();
if(!loop.isRunning()) {
loop.exec();
}
RequestFinishedHandler(reply);
// this is how I delete the reply object
delete reply;
}
RequestFinishedHandler(QNetworkReply *reply)
{
if (reply->error() > 0) {
QNetworkReply::NetworkError networkError = reply->error();
QString err = reply->errorString();
} else {
QVariant vStatusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
QMutexLocker lock(_pMutex); // _pMutex defined as class member
char *buffer;
buffer = getCurrentDateTime();
QTextStream out(m_file);
out << buffer << " " << _sCurrentUrl << "\n";
lock.unlock();
if(vStatusCodeV.toInt() == 200) {
QString ApiResponse;
QByteArray data;
data=reply->readAll();
ApiResponse.append(QString::fromUtf8(data));
}
}
}
It appears that to be effective, the deleteLater method must be called from within an event loop, which must regain control of execution to handle garbage collection.
Maybe you should refactor your code to have the event loop replace your while loop. Alternatively, since you're not using the finished slot to process the reply, perhaps you can delete the reply directly at the end of the RequestFinishedHandler function.

How to use a process (QProcess) in a new thread (QThread)?

I have the following code:
void Processmethod()
{
QDialog *ProcessMessage = new QDialog;
Ui::DialogProcessMessage Dialog;
Dialog.setupUi(ProcessMessage);
ProcessMessage->setModal(true);
ProcessMessage->setAttribute(Qt::WA_DeleteOnClose);
ProcessMessage->show();
qApp->processEvents();
processmethodONE();
processmethodTWO();
processmethodTHREE();
}
void processmethodONE()
{
QString ProcessCommand = "w8 " + blablubli";
Prozess.setWorkingDirectory(Path); //QProcess "Prozess" is globaly defined
Prozess.setStandardOutputFile(Path); //in my class
QThread* thread = new QThread;
Prozess.moveToThread(thread);
Prozess.start(ProcessCommand);
while(!Prozess.waitForFinished(2000))
{
std::cerr << "Process running " << std::endl;
}
QProcess::ExitStatus Status = Prozess.exitStatus();
if (Status == 0)
{
std::cout << "File created!" << std::endl;
}
}
In this source code I try to open a popup dialog before some processes are starting. problem is that the dialog is not clickable, but on the dialog I want to create a button to abort the running method. As you can see I tried using QThread to run the process(es) in another thread, but still I can't click the dialog. Furthermore if I open my application (GUI) with the "application/x-executable"-file the dialogs content is missing when activating the above shown method. How can I fix these problems? Where am I wrong? greetings
void processmethodONE()
{
QThread* thread = new QThread;
Prozess.moveToThread(thread);
Prozess.start(ProcessComand);
Here you moved the QProcess to another thread. But then you call start() on it. That's already not thread-safe.
while(!Prozess.waitForFinished(2000))
{
std::cerr << "Process running " << std::endl;
}
This blocks and makes using a thread useless. Also, it's not thread-safe.
You should instead not use threads but:
remove the waitForFinished() call
Connect the finished() and error() signals of the QProcess to slots which then start the next step, i.e. processMethodTWO.
I would also advise against reusing QProcess objects and just create a new one for each step.
While I still don't fully understand your recently updated code example, I feel this might be your issue:
while(!Prozess.waitForFinished(2000))
{
std::cerr << "Process running " << std::endl;
}
Wherever you are really calling this in your original code is blocking while waiting for Prozess to finish.
Use a brand new QProcess instance for each one, and connect their finished() signals to a SLOT that will get called when they have finished. Don't manually poll them and block. This will allow you to completely get rid of QThreads altogether.