A have a problem trying to stop my QProcess in it's parent destructor. Here is my code:
AbstractProcess::~AbstractProcess()
{
if((m_process->state() == QProcess::Running)
|| (m_process->state() == QProcess::Starting))
{
m_process->terminate();
m_process->waitForFinished();
}
}
m_process is a pointer to QProcess. In AbstractProcess's constructor I have this code:
m_process = new QProcess(this);
So, when AbstractProcess is deleted I get to it's destructor and I have a segmentation fault at :
m_process->waitForFinished();
Can anybody tell me what my mistake is?
UPD:
As was said below in the comments the problem was not in the code that I provided. Very sorry for that. So I will try to explain what the problem was. Maybe it will help somebody. AbstractProcess as you might guess by the name is an abstract class. So it has some pure virtual functions. On of them is:
virtual void onProcessFinished(int exitCode, QProcess::ExitStatus
exitStatus) = 0;
The full body of my constructor is:
m_process = new QProcess(this);
connect(m_process,static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
this, &AbstractProcess::onProcessFinished);
And now it's obvious that on calling waitForFinished the process emits signal finished and the pure virtual function is called. That leads to undefined behaviour. To fix this I call disconnect before stopping my process. The destructor now looks like this:
AbstractProcess::~AbstractProcess()
{
disconnect(m_process,static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
this, &AbstractProcess::onProcessFinished)
if((m_process->state() == QProcess::Running)
|| (m_process->state() == QProcess::Starting))
{
m_process->terminate();
m_process->waitForFinished();
}
}
Thanx everybody for your help.
When you call m_process->terminate(); first, there is no guarantee that the process will exit .. yet there is no guarantee that the process will continue to exist because of calling (WM_CLOSE on windows / SIGTERM on Linux) so calling for m_process->waitForFinished(); on a process that might have already been terminated might cause segmentation fault.
the right and safe approach is to do the right things in order:
m_process->waitForFinished();
m_process->terminate();
Related
I found time to investigate a bit into QT, and it is very interesting for me. However, right now I am encountering a problem that I am not aware about how to solve it. My aim is actually simple. I have a QCheckBox that I want to activate. If it is activated, I am starting a process (I am opening a file, reading it, taking some values out and change different labels accordingly). This process is repeated until the user is deactivating the QCheckBox. Some small code example to get a better idea of what I am going to do.
void Analyzer::on_actualTemperature_stateChanged(int arg1)
{
// Read data and change labels
if (arg1 != 0)
{
qDebug() << "Start data analysis";
// Infinity loop to get the data and display it
while true
{
// Open file and extract data
const actualTemperature = getData();
// Change any label or do something with the data
ui->anyLabel->setText(actualTemperature);
// Some break
QThread::sleep(1);
// Leave the loop if user deactivate the QCheckBox
// Something like on_actualTemperature_stateChange == 0
}
}
// Stop reading the data
else
{
qDebug() << "Stop data analysis";
}
}
It is obvious that after activating the QCheckBox, the loop will not finish at all and the GUI will not recognize anything anymore. Hence, I guess I have to start some new thread and have to kill it. However, I have no idea how to proceed here. An idea would be:
void Analyzer::on_actualTemperature_stateChanged(int arg1)
{
// Read data and change labels
if (arg1 != 0)
{
// Start reading the file and updating the label using some other thread
startThread(XY);
}
// Stop reading the data
else
{
// Kill thread 1234
killThread(XY);
}
}
Any hint is warmly welcomed and I hope this question is not too basic for you. Thank you for reading, Tobi.
I think killing a running thread is not a decent behavior. Let's be gentle to our threads with a loop control variable. In this example it named keepLoop. Set keepLoop when checkbox checked. Then start thread if it is not running. We are using QtConcurrent::run, and monitoring it by a QFuture in this case.
connect(ui->checkBox, &QCheckBox::toggled,
[&](const bool checked) {
analyzer->keepLoop = checked;
if (checked && !future.isRunning())
future = QtConcurrent::run(analyzer, &Analyzer::on_actualTemperature_stateChanged);
}
);
Don't call user interface slots directly, instead connect them to signals. Connections will be queued connection when signals emitted from another thread. It means slots will be called in event loop of main thread and changes will be shown when the next frame painted.
connect(analyzer, &Analyzer::temperatureCalculated, ui->anyLabel, &QLabel::setText);
Our asynchronous function does not forced to die immediately when user toggle checkbox. Instead we letting it to finish the iteration it already on halfway through.
Analyzer::on_actualTemperature_stateChanged() {
while (keepLoop) {
// Open file and extract data
const QString& actualTemperature = getData();
// send data
emit temperatureCalculated(actualTemperature);
}
}
You can use atomic bool if you want a more precise loop control.
Bonus:
If you don't want to mess with threads, you can avoid GUI freezing by using QTimer to run your loop periodically in main thread.
given this code:
void FooBar::ProcessExitHandler(QProcess* someProcess, QString logsPath)
{
if (clientProcess->exitCode() != 0)
{
QMessageBox* dialog = new QMessageBox();
dialog->setText("bye bye");
dialog->setStandardButtons(0);
QObject::connect(dialog, &QMessageBox::finished, [this](int) {
if (mMainWindow->AutoCloseCheckBoxChecked())
{
delete dialog; //TODO: need to confirm what is the correct way
this->quit();
}
});
dialog->show();
dialog->activateWindow();
}
else
{
if (mMainWindow->AutoCloseCheckBoxChecked())
{
delete dialog; //TODO: need to confirm what is the correct way
this->quit();
}
}
}
Is calling delete dialog like that correct? Is there a more QT idiomatic way of doing this?
Also, something that has caused me confusion is the idea (from the docs) that I should be passing a parent to the constructor of the message box. Then I would get automatic memory management, right? Is that the QT style I should shoot for?
I'm aware that since the app is exiting anyway, the leak "doesn't matter", but I want to do the right thing.
The right way is to use setAttribute
QMessageBox* dialog = new QMessageBox();
dialog->setAttribute(Qt::WA_DeleteOnClose);
By setting the attribute WA_DeleteOnClose, the destructor will be called at the right moment.
When you manually call delete, the pointer will keep its value (the address) although it isn't valid anymore. If for some reason you were to reuse that pointer again, the app would crash.
\warning Deleting a QObject while pending events are waiting to be
delivered can cause a crash. You must not delete the QObject directly
if it exists in a different thread than the one currently executing.
Use deleteLater() instead, which will cause the event loop to delete
the object after all pending events have been delivered to it.
https://code.woboq.org/qt5/qtbase/src/corelib/kernel/qobject.cpp.html#881
I am trying to fix a memory leak found is this code by val-grind. I did not write it, but I reduced the original code down to using ofstream and not filebuf and ostream.
The problem is I can't figure out how to properly delete the ofstream pointer which is shared and called from a virtual getter method in other code. I think this code violates the rule of 3 but trying different assignment and copy constructors did not work.
Below is an example of the basic code I am trying to fix, when it goes to delete the ofstream pointer is seg faults. Before the segfault I was getting a double delete error.
If anyone can please help, I seem to be stuck here, thanks.
class myLogger
{
public:
myLogger(std::string testName);
void createFileLog();
...
protected:
std::ofstream* my_LogStream;
};
void MyLogger::createFileLog()
{
if(Created == false)
{
m_pLogStream = new std::ofstream(logFileName.c_str(), std::ofstream::out);
Created = true;
}
}
myLogger::~myLogger()
{
if(m_pLogStream)
{
delete m_pLogStream;
m_pLogStream = NULL;
}
}
I found in a higher call it was using a copy and calling the destructor twice.
i have a function that is started by a QTconcurrent run. Inside this function i use QThread (To get the Thread created by the QTConcurrent run) static method to sleep it for some time, but i don't want anymore to use time to activate it, i'd like to use a WaitCondition to wake the thread in another point of the execution, but i searched a lot and don't find any case like this. I only see WaitConditions inside run() methods. Is there some way to use QWaitCondition in a thread started by QtConcurrent?
You also need a mutex:
void work(QMutex* mutex, QWaitCondtion* cond, volatile bool* wake){
//do work
{
QMutexLocker locker(mutex);
while(!*wake){
cond->wait(mutex);
}
}
//do more work
}
The loop is necessary to avoid spurious wakeups and let the thread fall through if wake is already set to true. Locking over the entire loop is needed to avoid various race conditions.
You wake the thread with:
{
QMutexLocker locker(mutex);
*wake = true;
cond->wakeOne();
}
is it okay to do something like this, the code snippet is of course not complete, just to show what I mean:
void draw(IplImage* image){
cvLine(image,cvPoint(20,20),cvPoint(100,100),cvScalar(0,0,255),1);}
int main(){
cvNamedWindow("preview",CV_WINDOW_AUTOSIZE);
IplImage* image;
image=cvCreateImage(cvSize(480,360),8,3);
while(true){
draw(image);
cvShowImage("preview",image);
int ops=cvWaitKey(10)
if ops!=-1 break;}
cvReleaseImage(&image);cvDestroyWindow("preview");return 0;
}
or will it cause problems if I don't return the IplImage like this:
IplImage* draw(IplImage* image){
cvLine(image,cvPoint(20,20),cvPoint(100,100),cvScalar(0,0,255),1);return image;}
well, the reason why I'm asking is that sometimes it works if I don't return the IplImage. However it may also happen that I'll receive some sort of NULL pointer error message in other cases. If for example I release the image in the function and then create it anew right after that, still being in that function, a crash may happen.
You don't need to return anything, but you definitely need to check for failures!
The problem is that you are not coding safely. You are never checking for failures when calling OpenCV functions, which may result in draw() receiving a NULL pointer as parameter, and that might cause a crash or some other weird behavior along the way.
The first thing you should do is start coding defensively:
IplImage* image = cvCreateImage(cvSize(480,360),8,3);
if (!image)
{
// print error and quit
}
and it wouldn't hurt to add a safety check inside your function:
void draw(IplImage* image)
{
if (!image)
{
// print error
return;
}
cvLine(image,cvPoint(20,20),cvPoint(100,100),cvScalar(0,0,255),1);
}