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

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.

Related

QT - slot preemption / interrupt

I'm trying to write an app for testing ST board via serial port and I'm currently facing the following issue. (The code below is just a simplification of a problem.)
Widget::Widget(QWidget *parent)
: QWidget(parent)
, m_button(new QPushButton(this))
, m_timer(new QTimer(this))
{
m_timer->setSingleShot(true);
connect(m_button, &QPushButton::released, this, &Widget::RunTest);
connect(m_timer, &QTimer::timeout, this, &Widget::OnTimeout);
}
void Widget::RunTest()
{
qDebug() << "Start test";
m_timer->start(1000);
while (m_timeout != true);
qDebug() << "Start end";
}
void Widget::OnTimeout()
{
qDebug() << "Timeout";
m_timeout = true;
}
I want to have a seprate class for gathering and running tests. The tests are triggered by clicking on a button. Some tests will have to send data via serial port and wait for the reply. I would like to be able to implement a timeout feature (if board doesn't reply then finish test with failure). However I the app is waiting for the m_timeout flag indefinitely. So my question is: Is there any signal/slot mechanism similar to interrupt preemption? If no how sush problems are solved in Qt? Shall I create seprate QTimer object and run it in separate thread?

passing information on Threaded TcpServer from one thread to another

I tried to create simple server like in link 1.
Youtube tutorial to create multithreaded server
void Test_Server::incomingConnection(int socketDescriptor_)
{
qDebug() << socketDescriptor_ << "connecting...";
Test_Thread *thread_ = new Test_Thread(number_,socketDescriptor_,this);
connect(thread_,SIGNAL(finished()),thread_,SLOT(deleteLater()));
thread_->start();
number_++;
}
////
void Test_Thread::run()
{
qDebug() << this->Socket_Descriptor_ << "starting thread";
socket = new QTcpSocket();
if(!socket->setSocketDescriptor(Socket_Descriptor_))
{
qDebug() << "ERROR";
}
connect(socket,SIGNAL(readyRead()),this,SLOT(Ready_read_()),Qt::DirectConnection);
connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected_()),Qt::DirectConnection);
qDebug() << this->Socket_Descriptor_ << "Client connected";
QByteArray name = QByteArray::number(number_);
server_->Socket_map_.insert(name,this);
server_->show_all_connected_sockets_();
exec();
}
My goal is to connect two clients to server(i use telnet), write from Client 1 to server something, and server should pass data to Client 2.
To do that I've made QMap to storage pointers to MyThreads. When data is received from Client 1, I'm calling method:
void Test_Server::write_to_client_(int number, QByteArray data)
{
QByteArray name = QByteArray::number(number);
Test_Thread *pointer;
pointer = client_socket_(name);
connect(this,SIGNAL(send_data_(QByteArray)),pointer,SLOT(write_data_(QByteArray)));
emit send_data_(data);
disconnect(this,SIGNAL(send_data_(QByteArray)),pointer,SLOT(write_data_(QByteArray)));
qDebug() << "void Test_Server::write_to_client_(int number, QByteArray data): data sent";
}
////
void Test_Thread::write_data_(QByteArray data) const
{
socket->write(data);
socket->waitForBytesWritten();
}
Generally passing information works, I write in Client 1 some data, and Client 2 shows it, however I'm geting:
TQObject: Cannot create children for a parent that is in a different
thread.
Parent Test_Thread is QNativeSocketEngine(Pointer 1), parent's thread is >(Pointer 2), current thread is (Pointer 3);
QsocketNotifier: Socket notifiers cannot be enabled or disabled from another thread.
My question is: how to correctly pass data from client 1, to server, and then to client 2? I've done reasearch and problem lies in proper use of Signals and Slots but I cannot find out how to do it in proper way.
Test_Thread::write_data is not running on the same thread where the socket was created, that is Test_Thread::run(). In the QThread class, only what runs on the run method runs on a separate thread.
I finally solved issue. To do that i followed similar issue solution described here: PROBLEM & SOLUTION
I've resigned to use class MyThread, instead created class Worker and moved it to thread like here below:
void Test_Server::incomingConnection(int socketDescriptor_)
{
qDebug() << "void Test_Server::incomingConnection current thread: " << QThread::currentThread();
qDebug() << socketDescriptor_ << "connecting...";
Socket_map_.insert(number_,QByteArray::number(socketDescriptor_));
QThread *thread_= new QThread;
qDebug() << "void Test_Server::incomingConnection new thread_: " << thread_->thread();
Test_Worker *worker = new Test_Worker(socketDescriptor_);
worker->moveToThread(thread_);
connect(thread_,SIGNAL(started()),worker,SLOT(create_socket_()));
connect(this,SIGNAL(pass_socket_descriptor_(int)),worker,SLOT(set_socket_descriptor_(int)));
connect(worker,SIGNAL(finished()),thread_,SLOT(quit()));
connect(worker,SIGNAL(finished()),worker,SLOT(deleteLater()));
connect(thread_,SIGNAL(finished()),thread_,SLOT(deleteLater()));
connect(worker,SIGNAL(pass_data_to_server_(QByteArray,QByteArray)),this,SLOT(data_from_socket_(QByteArray,QByteArray)));
connect(this,SIGNAL(pass_data_to_client_(QByteArray,QByteArray)),worker,SLOT(show_data_received_from_server_(QByteArray,QByteArray)));
number_++;
thread_->start();
}
HINT: When i created socket via test_server signal create_socket_(int)
and socket create_socket(int), program didn't work correctly. To fix
that connect signal from starting thread to socket - create_socket_
Program now succesfuly without errors receive data from client 1 and pass it to client 2.

QProcess does not complete creating file

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();

Qt get a threads ID in the main thread?

I have some issues with this:
First I create my object and move it to a thread:
FileUploader *fileUploader = new FileUploader(fileList_, start, (offset == 0 ? (fileList_.count() - start) : offset));
QThread *fileUploaderThread = new QThread;
fileUploader->moveToThread(fileUploaderThread);
fileUploaderThreads_.append(fileUploaderThread);
fileUploaders_.append(fileUploader); // contains pointers to the objects
connect(fileUploader, SIGNAL(progressChangedAt(int)), model_, SLOT(reportProgressChanged(int)), Qt::QueuedConnection);
connect(fileUploader, SIGNAL(statusChangedAt(int)), model_, SLOT(reportStatusChanged(int)), Qt::QueuedConnection);
connect(fileUploader, SIGNAL(finished()), fileUploaderThread, SLOT(quit()), Qt::QueuedConnection);
connect(fileUploaderThread, SIGNAL(finished()), this, SLOT(checkIfFinished()), Qt::QueuedConnection);
The in the slot checkIfFinished() I wanna go though all the threads and see if they quit.
qDebug() << "one thread done";
foreach(QThread *thread, fileUploaderThreads_) { // or FileUploader* fileuploader, fileUploaders_ ?
if(thread && !thread->isFinished()) {
qDebug() << "not finished " << thread->currentThreadId();
return; // not done
}
}
When this is printed out, I only get the main thread Id, not the threads. I tried to print the threads id's out but with no luck (after they are started ofc).
The reason why I'm doing this I because the person writing "Advanced Qt Programming - Mark S" did a similar thing with QThreads that he placed in a list and checked if they where finished. The only thing thats working now is the connection which kills the thread when the fileUploader is done.
Also, how do I store pointers for the threads? I wounder how I will be able to delete them all if they don't seem to point to the right threads.
Edit:
I tried to store the QObjects in a list instead and do this:
QThread *senderx = qobject_cast<QThread*>(sender());
qDebug() << "one thread done" << senderx;
foreach(FileUploader *fileUploader, fileUploaders_) {
if(fileUploader && !fileUploader->thread()->isFinished()) {
qDebug() << "not finished " << fileUploader->thread();
return; // not done
}
}
//done
qDebug() << "done";
setButtonState(false);
And my outprint on the last call is :
one thread done QThread(0x43ee180)
not finished QThread(0x43ee180)
How is this possible? It is done, but the method says otherwise.
you want QObject::thread(), not QThread::currentThreadId() - the second one returns the thread that the function was called in.
Once you fix that, your pointers will work fine.

Using Custom Events in QT4

I have an app that has a progress bar & spawns a worker thread to do some work & report back progress. The dialog class overrides the customEvent method so that I can process events that are being passed to the gui thread via the worker thread. Before I was using a QThread derived class as the worker thread and I changed it to use ACE_Thread_Manager->spawn() with a static function for the worker.
The problem shows up when I run the app and press the button so the worker is spawned & starts doing work. When it sends the signal to increment the progress bar I get the following errors logged to std out.
QPixmap: It is not safe to use pixmaps outside the GUI thread
This seems to happen when the progressBar->setValue() is called. So it seems like the setting of the progress bar is happening in a different thread than the main gui thread. I'm unclear as to how that's possible. I'm under the impression that I have a main gui thread which has my gui & the customEvent method is on that same thread and the worker is on it's own thread. Is this assumption wrong? And is there any difference when using the QThread derived class versus the static run_svc method?
Any help would be appreciated. The code snippets for the customEvent handler, run_svc, and button handler code are below and the code is attached.
void MyDlgEx::customEvent(QEvent * e)
{
if (e->type() == IdNumOperations)
{
NumOperations* pEvt = static_cast<NumOperations*>(e);
_steps = 0;
cout << "Num Operations = " << pEvt->operations() << endl;
}
else if (e->type() == IdStep)
{
if (_steps % 10 == 0)
{
cout << "Step++ = " << _steps << endl;
}
_steps++;
_progressBar->setValue(_steps);
}
}
void* MyDlgEx::run_svc(void* args)
{
auto_ptr<ThreadArgs> thread_args(static_cast<ThreadArgs*>(args));
QApplication::sendEvent((QObject*)thread_args->m_pDlg, new NumOperations(300));
// does some work that takes time -- ommitted for clarity
// called in a loop
QApplication::sendEvent((QObject*)thread_args->m_pDlg, new Step());
QApplication::sendEvent((QObject*)thread_args->m_pDlg, new Completed());
return 0;
}
Button Handler
Commented out lines where where I used a QT class derived from QThread. Using ACE has to spawn the thread has uncovered this issue.
void MyDlgEx::btnShowProgress_clicked()
{
//_pProc = new ProcessThread(this);
//_pProc->run();
auto_ptr<ThreadArgs> thread_args(new ThreadArgs(this));
if (ACE_Thread_Manager::instance()->spawn(
MyDlgEx::run_svc,
static_cast<void*>(thread_args.get()),
THR_DETACHED | THR_SCOPE_SYSTEM) == -1)
cout << "Failed to spawn thread." << endl;
thread_args.release();
}
Try calling QApplication::postEvent(...) instead of QApplication::sendEvent(). The docs say that sendEvent sends the event directly, meaning that it calls the customEvent() function directly from the other thread. postEvent() adds the event to the event queue where it can later be dispatched to customEvent() by the main GUI event loop.
Just because the customEvent() function is a member of an object created in the main GUI thread doesn't mean another thread cannot call the function. I believe that is what is happening when you call QApplication::sendEvent() from another thread.