Introduction
Lets say I have an app with GUI, which gathers some data from the user and then call an embedded python script. I want to add "cancel button" in case the user want to stop the process.
Exemplary code
mainwindow
#include "calc_script.h"
signals:
void stopWorkSignal();
private:
calc_script *sender;
private slots:
Calculating()
on_pushButton_Cancel_clicked()
void MainWindow::Calculating()
{
QThread* newThread = new QThread();
connect(newThread, &QThread::started,
[=]() { sender->transfer(val_1, val_2, val_3); });
connect(this,
SIGNAL(stopWorkSignal()),
newThread,
SLOT(deleteLater())
newThread->start();
}
void MainWindow::on_pushButton_Cancel_clicked()
{
emit stopWorkSignal();
qDebug() << "stopwork signal emmitted";
}
calc_script.cpp
void calc_script::transfer(double val_1, double val_2, double val_3)
{
///Here the python (from boost.python) is executed
while(1) {}//this loop will generate a load to mimic this script, you cannot edit it, as the communication with .py is one-side at this lvl
}
The problem
When the signal is called I got the error QThread destroyed while thread is still running (and calculation seems to be still going). If I pass SLOT(quit()), nothing happens. If the calculation would be simple loop, I could pass a flag, to brake the loop. But due to calling python script I'm unable to do this, so I'm trying with destroying the Thread which hold the calculations. What's the correct way to do described functionality?
PS. I know I didn't included entire call to python but it is very long. For the reproduction error you can use any non-loop long calculations inside transfer function, it will do basically the same situation.
You can't forcibly terminate a thread; all you can do is ask it to quit, and then wait for it to exit of its own accord. (there does exist a QThread::terminate() method, but you shouldn't use it in production code, as it will cause problems: for example, if the thread had a mutex locked at the moment it got terminated, that mutex will remain locked forever, and your program will deadlock and freeze up the next time it attempts to lock that mutex).
So you have two options: either figure out a way to ask the Python thread to quit, or use a QProcess object (or something equivalent to it) to run the Python code in a child process instead of inside a thread. The benefit of running the Python code in a separate process is that you can safely kill() a child process -- since the child process doesn't share any state with your GUI process, and the OS will automatically clean up any resources allocated by the child process, there is no problem with the child process leaving mutexes locked or other resources un-freed.
If you'd rather ask the Python thread (or process) politely to exit instead of simply bringing down the hammer on it, you could do so via a networking interface; for example, you could create a TCP connection between your GUI code and the Python event loop, and the Python event loop could periodically do a non-blocking read on its end of the TCP connection. Then when your GUI wants the Python loop to exit, the GUI could close its TCP socket, and that would cause the Python loop's call to read() to return 0 (aka EOF), which the Python loop would know means "time to exit", so it could then exit voluntarily.
Related
I'm working on a project that uses uses a thread to connect to a server. Whenever the login button is pressed, it initialized a thread to log in with the given IP and port provided by the user.
ServerPage.h
class ServerPage {
public:
static std::thread serverThread;
static void login();
}
ServerPage.cpp
#include "ServerPage.h"
std::thread ServerPage::serverThread;
void ServerPage::login() {
while (/*server is not connected*/) {
if (/*button is clicked and thread is not running*/)
serverThread = std::thread(Client::init, ip, port);
}
}
This works well until the button is clicked more than once. I'm able to use the Client class to see the status of the server (connected, not connected, or failure) Is there a way to delete or re initialize so that it can be run until the client is connected?
First of all: threads cannot be restarted. There is no such concept in programming. Unless by "restart" you mean "kill and spawn again".
It is not possible to kill a thread in a cross-platform way. For posix (I don't know about other OS) you can use pthreads (instead of std::thread) and send kill signal to it and spawn it again. But this is a ninja way, not necessarily what you should do. For example if you kill a thread that currently holds a lock, you will end up in a deadlock. This method should be avoided. However, if you can't modify Client::init method, then there might be no other choice without weakening your requirements.
A better solution is to pass around "cancellation tokens": small objects that you can register cancel handlers on it. Then you implement Client::init to cancel itself (and do any necessary cleanup, like releasing locks) whenever cancellation is triggered. Which you trigger on click.
I'm making a render job manager for blender. I have a class that builds up a queue of render jobs and then you click Start and it begins rendering one at a time with a loop. My problem is that the waitForFinished() method holds up my entire program. But I've read that you shouldn't use QThread with QProcess.
This is how the loop works.
do{
if(myProcess->state() == QProcess::NotRunning) {
myProcess->setProgram(blenderPath);
myProcess->setArguments(arguments);
myProcess->start();
myProcess->waitForFinished(-1);
//Get rid of current rendering job to prepare for the next job
renderQueueList.pop_front();
}
}while(renderQueueList.empty() != true);
Can I use a separate thread to launch QProcess and what would be the best way to do this? I've read that you make an abstract of QThread or use signals and slots but it's so confusing, specially when I need to pass arguments to the process.
Thank you.
Edit:
I want to add that the process must finish before running a new process. It has to go in order. That's why I think I need the process to run in its own thread.
QProcess already executes in a different process, i.e. asynchronously with your application.
When you call waitForFinished() the application locks up until the process in QProcess finishes. You need to connect instead to the finished() and probably errorOccured() signals, and then your application will keep running while the QProcess runs in the background.
You'll need to change that loop to a check that the queue isn't empty and a new process start on the finished() signal.
If you run a QThread that runs QProcesses and does waitForFinished() you will free the main application thread indeed, but it's a pointless extra layer when QProcess is asynchronous already and you have have finished() to let you know when it's done without locking up a thread, be it the UI thread or a separate one.
I have just started working with QT, and found the nice feature of QTTimer which triggers the slot at the interval of given period. Some point in time, I came across two situations.
1) if the timer is in the pending state, stopping timer have no issues that i won't even move to 'running state'.
2) If the timer is already running ( assume it is a bit long process task), then i found the stop will not terminate/stop 'running state'.
My Question:
At any given point of time, if stop is invoked, i should make sure it is stopped if it is already running.
Example:
connect(&myTimer,SIGNAL(timeout()), this, SLOT(missionStarted()));
When i Stop like this:
myTimer.stop() -> It actually stops the next firing the signal, but it does not stop running state of missionStarted().
What i thought of a solution ?
myTimer.stop();
while (myTimer.isActive()) {
}
qDebug()<<" I am guaranteed that missionStarted() is no more running, will not run anymore" ;
Is the solution is a way to go?. please guide me.
Does Qt Timer API stop and terminate the running slot?
No. The timer stop does not terminate running slot.
And how can I make it wait to get the timer slot execution completed?
There several ways to do so: with the signal back to the object that has the timer, for instance:
void MyWorkerClass::mySlot()
{
doTheJob();
emit signalIamDone();
}
And the the object that has the timer can acknowledge the slot stopped by connecting to that signalIamDone:
connect(&workerObj, SIGNAL(signalIamDone()), &managerObj, SLOT(workerJobDoneSlot()));
The actual slot:
void MyManagerClass::workerJobDoneSlot()
{
doSomethingOnJobFinished();
}
I would also try to use condition variable wait if you had a manager and worker thread but it seems like everything is running on one main UI thread.
And mind that usually the worker slot is getting called on the same main thread as your manager object runs unless your manager object is specifically running in the context of own thread. So, unless told otherwise about threads, you always have it waiting on the slot finishing you just need to know that the wait is over or doSomethingOnJobFinished called.
I am developing a windows form application with Qt 5.0.2. I need to call another program during mine, which is a console application. I want to pass the arguments through command line or a file, and read the expecting results via another file, but, because of some reasons I need to when the program finishes its work and the expecting file is ready to be read.
My process is defined as follow :
QProcess *p;
p = new QProcess(this);
QStringList args;
args << "babak" << "Ali" << "Mohsen";
p->execute("ConsoleApplicationCSH.exe" ,args)
I know I could use start instead of execute, but the result was the same. I tried to check it out through this code:
while(!p->waitForFinished()){
;
}
exit(1);
The called is written is way that it takes around 10 sec to finishes it process, but the while loop does not finishes. I checked the other form of using this method and some similar methods but I didn`t get any good result.
First, you need to use QProcess::start() instead of QProcess::execute(): execute() is a static method running the process and blocking until it's done. So the process is already finished when execute() returns. Use start() to run the process without blocking.
Then, in GUI code, you should connect to the finished() and error() signals to learn about both successful termination and errors (check errorString() in case of errors).
If run in the main thread, waitForFinished() blocks the UI, thus it's usually undesirable to use the blocking calls. Note that waitForFinished() returns false not only on timeout, but "if the operation timed out, if an error occurred, or if this QProcess is already finished". Connecting to finished() and error() is a more robust way to detect error cases. If you really want to it in a blocking way (e.g. in a secondary thread or in a non-GUI program), call QProcess::waitForStarted() first, to detect cases where the process couldn't even be started more cleanly.
My windows/QT application is not exiting consistently.
After the object clean up, I am trying to delete the QProcess object. But it's not cleaning up the process and it can be shown in the task manager.
delete process;
process = 0;
I think delete process is not working because some threads are running at the background. I want to ensure that all threads are closed gracefully, so the process will exit.
Please let me know the right way to do this.
The task manager does not show your QProcess object, and deleting that object will not affect the task manager. If there is still code running in your process, the process will continue to exist according to the OS.
If you really want to exit the process, you can call the Win32 function ExitProcess(). Just make sure you've saved everything you want to.
Qt will normally exit the process when all your threads stop running.
One problem may be that the QProcess object doesn't represent a child thread, it represents an independent process, you probably want to use the QThread object.
With the QThread object you can use some combination of the quit, exit, wait, and terminate depending on the exact content of you child thread, check the documentation for the differences.