Qt 4.8 killing and restarting the GUI - qt

There is requirement of writing a Qt application on a MIPS based platform.
But there are lots of constraints. The constraints included freeing up of few resources (QGFX Plugin, GPU Memory etc) when required and re-using it. But the application cannot be killed as its handling lots of other requests and running other things.
Basically the GUI needs to be killed and free all the resources related to GUI; later when when required restart again
One of the way which has been tried is :
main() -> create a New-Thread
In the New-Thread,
while(<Condition>)
{
sem_wait(..)
m_wnd = new myMainWindow();
...
..
app->exec();
}
When ever there is a kill command, it comes out of the event loop, and wait for the signal from other threads. Once other threads does the required changes, it will get the signal and will create a new window and goes into the event loop.
In the main(), there are also few other threads created, which control other devices etc and signal the start and stop for the Qt-GUI.
The above seems to work but I am not sure if this is the right design. Does it create any problem?
Can any one suggest any better way?

I was able to find the required answer in Qt-Forums.
Since the main intention was to remove all the things related to GUI (On screen), I could use void setQuitOnLastWindowClosed ( bool quit ) (Details Here). This will make sure the GUI / Main window is closed and still the app doesnt come out of event loop and I can restart the main window later.
Thanks

When I needed a way to ensure that my app kept running, I forked it into a sub-process. That way, even if it seg-faulted, the main process would catch it and start a new child process. In the child process, I had multiple threads for GUI and non-GUI tasks. The fork code is short and is based on the example given in the wait(2) man page. The main() simply calls createChild() in a while loop. createChild() starts a new process using zmain(). zmain() is your QT app's main.
#include <QtGui/QApplication>
#include <QThread>
int zmain(int argc, char *argv[])
{
QApplication app(argc, argv, true);
app.setQuitOnLastWindowClosed(false);
QThread powerThread;
Power p;
p.moveToThread(&powerThread);
powerThread.start();
return app.exec();
}
// The following code is taken from the wait(2) man page and has been modified to run
// our Qt main() above in a child process. When the child terminates, it is automatically
// restarted.
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int createChild(int argc, char *argv[]) {
pid_t cpid, w;
int status;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Code executed by child */
fprintf(stderr, "Child PID is %ld\n", (long) getpid());
exit(zmain(argc, argv));
} else { /* Code executed by parent */
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
return(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
fprintf(stderr, "exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
fprintf(stderr, "killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
fprintf(stderr, "stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
fprintf(stderr, "continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
if (WIFEXITED(status) && WEXITSTATUS(status) == 111)
return 111;
return EXIT_SUCCESS;
}
}
int
main(int argc, char *argv[])
{
while (111 != createChild(argc, argv)) {
}
}

Related

How to close GLFW window when we close QT application

When i close the QT GUI i want the GLFW window to be closed accordingly.
For glfw we can query if window is closed or not by glfwWindowShouldClose function.
Do we have anything like that in QT where we can keep Querying if the application GUI is closed.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TreeModel model;
QTApplication w(model);
int return_code = 0;
QTApplication.show();
glfwInit();
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, 4);
window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Renderer", nullptr, nullptr); // Create the render window
if (window == NULL)
{
QMessageBox msgBox;
msgBox.setText("Not able to create GL Window");
msgBox.exec();
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
GLenum GlewInitResult;
glewExperimental = GL_TRUE;
GlewInitResult = glewInit();
if (GLEW_OK != GlewInitResult) // Check if glew is initialized properly
{
glfwTerminate();
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
while (!glfwWindowShouldClose(window))
{
// Do Rendering here
}
return_code = a.exec();
glfwTerminate();
return return_code;
}
}
There is a signal for that, emitted by the application:
QGuiApplication::lastWindowClosed()
It looks like what you want to do is intermangle the Qt event loop with your own loop. Here is a hint about how to do that from the Qt docs:
To make your application perform idle processing (i.e. executing a special function whenever there are no pending events), use a QTimer with 0 timeout. More sophisticated idle processing schemes can be achieved using processEvents().
So this is how I would approach this:
Setup a QTimer that connects to a method that does rendering (if window should not close) and restarts the timer
Call a.exec()
In the method called by the timer, if window should close, call a.quit()

How to prevent the QBasicTimer::stop: Failed warning when objects become threadless?

QObjects can easily become threadless, when their work thread finishes ahead of them. When this happens, Qt doesn't release their timer ids, even though the timers are not active anymore. Thus, a QBasicTimer::stop: Failed. Possibly trying to stop from a different thread warning appears. It has mostly cosmetic consequences, but does indicate a timer id leak, and thus a workaround would be nice to have. The following example triggers the problem:
#include <QtCore>
int main(int argc, char *argv[]) {
static_assert(QT_VERSION < QT_VERSION_CHECK(5,11,0), "");
QCoreApplication app(argc, argv);
QObject object;
object.startTimer(1000);
QThread workThread;
workThread.start();
object.moveToThread(&workThread);
QTimer::singleShot(500, &QCoreApplication::quit);
app.exec();
workThread.quit();
workThread.wait();
}
It'd be nice if the workaround didn't have to make any modifications to how the timers are allocated, i.e. that there would be no extra tracking of timers needed beyond what Qt already does.
A simple solution is to prevent the problem: if the object is about to become threadless, move it to the thread handle's parent thread, and then when the thread itself is about to be destructed, reestablish the object's timers to prevent the warning.
QObject's moveToThread implementation has two parts:
The QEvent::ThreadChange is delivered to the object from moveToThread. QObject::event uses this event to capture and deactivate the timers active on the object. Those timers are packaged in a list and posted to the object's internal _q_reactivateTimers method.
The event loop in the destination thread delivers the metacall to the object, the _q_reregisterTimers runs in the new thread and the timers get reactivated in the new thread. Note that if _q_reregisterTimers doesn't get a chance to run, it will irrevocably leak the timer list.
Thus we need to:
Capture the moment the object is about to become threadless, and move it to a different thread, so that the QMetaCallEvent to _q_reactivateTimers won't be lost.
Deliver the event in the correct thread.
And so:
// https://github.com/KubaO/stackoverflown/tree/master/questions/qbasictimer-stop-fix-50636079
#include <QtCore>
class Thread final : public QThread {
Q_OBJECT
void run() override {
connect(QAbstractEventDispatcher::instance(this),
&QAbstractEventDispatcher::aboutToBlock,
this, &Thread::aboutToBlock);
QThread::run();
}
QAtomicInt inDestructor;
public:
using QThread::QThread;
/// Take an object and prevent timer resource leaks when the object is about
/// to become threadless.
void takeObject(QObject *obj) {
// Work around to prevent
// QBasicTimer::stop: Failed. Possibly trying to stop from a different thread
static constexpr char kRegistered[] = "__ThreadRegistered";
static constexpr char kMoved[] = "__Moved";
if (!obj->property(kRegistered).isValid()) {
QObject::connect(this, &Thread::finished, obj, [this, obj]{
if (!inDestructor.load() || obj->thread() != this)
return;
// The object is about to become threadless
Q_ASSERT(obj->thread() == QThread::currentThread());
obj->setProperty(kMoved, true);
obj->moveToThread(this->thread());
}, Qt::DirectConnection);
QObject::connect(this, &QObject::destroyed, obj, [obj]{
if (!obj->thread()) {
obj->moveToThread(QThread::currentThread());
obj->setProperty(kRegistered, {});
}
else if (obj->thread() == QThread::currentThread() && obj->property(kMoved).isValid()) {
obj->setProperty(kMoved, {});
QCoreApplication::sendPostedEvents(obj, QEvent::MetaCall);
}
else if (obj->thread()->eventDispatcher())
QTimer::singleShot(0, obj, [obj]{ obj->setProperty(kRegistered, {}); });
}, Qt::DirectConnection);
obj->setProperty(kRegistered, true);
}
obj->moveToThread(this);
}
~Thread() override {
inDestructor.store(1);
requestInterruption();
quit();
wait();
}
Q_SIGNAL void aboutToBlock();
};
int main(int argc, char *argv[]) {
static_assert(QT_VERSION < QT_VERSION_CHECK(5,11,0), "");
QCoreApplication app(argc, argv);
QObject object1, object2;
object1.startTimer(10);
object2.startTimer(200);
Thread workThread1, workThread2;
QTimer::singleShot(500, &QCoreApplication::quit);
workThread1.start();
workThread2.start();
workThread1.takeObject(&object1);
workThread2.takeObject(&object2);
app.exec();
}
#include "main.moc"
This approach can be easily extended to dynamically track all children of obj as well: Qt provides sufficient events to do such tracking.
Hold the timer id to be killed from within thread - by object:
int id = object.startTimer(1000);
QThread workThread;
workThread.start();
object.moveToThread(&workThread);
QTimer::singleShot(500, &QCoreApplication::quit);
QObject::connect(&workThread, &QThread::finished, [&](){object.killTimer(id);});
...
How about moving the object back to the main thread...
class Object : public QObject
{
public:
using QObject::QObject;
virtual ~Object() {
qDebug()<<"Object"<<QThread::currentThread()<<this->thread();
if(thread() == Q_NULLPTR)
moveToThread(QThread::currentThread());
}
};
#include <QtCore>
int main(int argc, char *argv[]) {
static_assert(QT_VERSION < QT_VERSION_CHECK(5,11,0), "");
QCoreApplication app(argc, argv);
Object object;
object.startTimer(1000);
QThread workThread;
workThread.start();
object.moveToThread(&workThread);
QTimer::singleShot(500, &QCoreApplication::quit);
qDebug()<<"main"<<QThread::currentThread()<<object.thread();
app.exec();
workThread.quit();
workThread.wait();
}

QT add Item trigger redraw, not freezing

i'm using QT for the first time and got some problems with refreshing the GUI while adding elements.
The Code looks like:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
PObj obj;
MainWindow mw;
qRegisterMetaType<std::string>();
QObject::connect(&obj, SIGNAL(setText(std::string const&)),
&mw, SLOT(appendText(std::string const&)));
QFuture<void> f1 = QtConcurrent::run(&obj, &PObj::process);
mw.show();
f1.waitForFinished();
return a.exec();
}
With the PObj::process definition:
void PObj::process()
{
for(; ;)
{
sleep(1);
//do work and set text
std::string text = "bla";
emit setText( text );
}
}
And the MainWindow::appendText slot:
void MainWindow::appendText(std::string const& str )
{
ui->listWidget->addItem(QString::fromStdString(str));
}
I've tried placing qApp->processEvents() ,QCoreApplication::processEvents(); ... running wit future in the ThreadPool.
I thought running them with Concurrent::run is enough ?
UPDATE:
The question is, why the GUI isnt refreshed every second a new item is added ?
The f1.waitForFinished(); calls blocks until f1 is finished, as the name implies. This will never happen because you have the infinite loop. So your code will never get to main loop. You can't block the main thread like that! In general, avoid any WaitForXxxx() methods, especially the GUI thread.
Also, you have no way of stopping the process(); anyway, so waiting for it to finish doesn't make any sense... You might want to add a way to tell it to stop (such as atomic variable) but anyway, to fix your problem, simply remove the f1.waitForFinished(); line.
To terminate the task nicely, try adding QAtomicInt flag (not volatile boolean, it won't do), and then change the code like this:
Add member variable to PObj (should make it private and add setter):
QAtomicInt termianteFlag;
Change main like this:
int main(int argc, char *argv[])
{
///snip
QFuture<void> f1 = QtConcurrent::run(&obj, &PObj::process);
mw.show();
int ret = a.exec();
f1.terminateFlag = 1; // change this to setter method
f1.waitForFinished(); // this is not ideal, will wait for up to a second before exit
}
and
void PObj::process()
{
while(!terminateFlag)
{
sleep(1);
//do work and set text
std::string text = "bla";
emit setText( text );
}
}

Qt: Single instance application with QSharedMemory

I looked up several examples how to create a single instance application and they all used create() and attach() methods of QSharedMemory. Why do they need attach()?
This seems to work perfectly:
bool SingleInstanceApplication::useSharedMemory()
{
_sharedMemory.setKey(_uniqueKey);
// If shared memory is created and attached successfuly,
// no other application instace is running
bool hasNoPreviousInstance = _sharedMemory.create(1);
return !hasNoPreviousInstance;
}
According to my understanding of the documentation. This has to be enough.
One example would be: http://developer.nokia.com/community/wiki/Run_only_one_instance_of_a_Qt_application
They need attach() because create() may fail for other reasons that the segment already exists. For example the system may be out of resources, or a shared memory segment creation is disabled for your application (by SELinux for example). In this case create() will return false but error() will return a different error code (such as QSharedMemory::OutOfResources) and you won't be able to find out that a segment already exists, while attach() would find it out.
I test a minimal case on a Linux distro:
#include <QCoreApplication>
#include <QSharedMemory>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
const char* MEM_KEY = "42";
QSharedMemory sharedMem(MEM_KEY);
if (sharedMem.create(1024)) {
qDebug() << "Create shared memory";
} else {
if (sharedMem.error() == QSharedMemory::AlreadyExists) {
qWarning() << "Already create. Exiting process";
return 1;
} else {
// handle other possible errors
}
}
return a.exec();
}
As you suggest, a call to create seems enough to make the attended error occur. In my understanding, attach is only called when a second process want to access an already created shared memory. But, that's not the purpose of a single application guard.

QSharedMemory::handle doesnt exist error

I'm trying to run the following QT code :
#include <QtCore/QCoreApplication>
#include <QSharedMemory>
#include <QDebug>
QSharedMemory g_objSharedMemory(QString("Shared Memory"));
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
if(g_objSharedMemory.isAttached()==false)
{
qDebug()<<"Shared memory is not attached !!!!trying to attach it\n ";
qDebug()<<g_objSharedMemory.errorString();
if(g_objSharedMemory.attach()==false)
{
qDebug()<<"Failed to attach shared memory to the process!!!!";
qDebug()<<g_objSharedMemory.errorString();
return 0;
}
}
return a.exec();
}
I've failed to attach the shared memory segment to the process. I'm building this code on windows XP.
I'm getting QSharedMemory::handle doesnt exist error.
How can i fix this error?
You need to create() the shared memory segment in one of the processes which are using it. Most likely, you have one "master" or "server" process which is started first - let this process create the shared memory with a specific size:
qDebug()<<"Creating shared memory ...";
if(g_objSharedMemory.create(42) == false) {
qDebug() << "Failed to create shared memory!!!!";
qDebug() << g_objSharedMemory.errorString();
}
Then, in your "slave" or "client" processes, you should be able to attach to the shared memory with the same key.
Note that create() also attaches the process, so you must not call attach() in the master process.

Resources