Non locking calls via python console for PythonQt library - c++

My Qt application has a Qt gui (basically some buttons and an opengl context which draws data). I've also added scriptability exploiting PythonQt classes. The commands are evaluated from inside a PythonQtScriptingConsole.
I've explicitly created wrapper classes and factory methods to send C++ calls via the current python context through the console, but when running long tasks from inside the console, the gui freezes because (I think) the event loop is not processed. So a first solution would be to process the event loop with a timer, but this is both slow and kinda stupid I think, so I don't like it. A
Has someone some hint? Is the Python Global Interpreter Lock a problem here?

Yes, the GUI is freezing because the long call into Python is being executed via the UI thread. To get around this, I was able to subclass QThread and issue commands into the Python module via a Command pattern.
Before you start making calls into multiple Python modules using the following classes, be sure to initialize thread support in Python by calling PyEval_InitThreads() as you'll see in my main() function.
Good luck!
int main( int argc, char **argv ) {
QApplication qapp(argc, argv);
PyEval_InitThreads(); // IMPORTANT
PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
PythonQtObjectPtr module = PythonQt::self()->createUniqueModule();
ThreadedPythonContext context(module);
context.start();
# issue some commands into the module
context.issue("import sys");
context.issue("sys.path.append('C:\\Python27\\Lib\\site-packages')");
context.issue("import time");
context.issue("last = time.localtime().tm_sec");
// Release the global interpreter lock (if it has been created and thread support
// is enabled) and reset the thread state to NULL, returning the previous thread
// state (which is not NULL). If the lock has been created, the current thread must
// have acquired it. (This function is available even when thread support is
// disabled at compile time.)
// give up control of the GIL
PyThreadState *state = PyEval_SaveThread();
return qapp.exec()
}
ThreadedPythonContext.h
#ifndef THREADEDPYTHONCONTEXT_H
#define THREADEDPYTHONCONTEXT_H
#include "PythonQt.h"
#include <QtCore/QMutexLocker>
#include <QtCore/QQueue>
#include <QtCore/QThread>
#include <QtCore/QWaitCondition>
class ThreadedPythonContext : public QThread
{
Q_OBJECT
public:
ThreadedPythonContext(const PythonQtObjectPtr &context) :
QThread(),
_context(context),
_running(true)
{
}
~ThreadedPythonContext() {
_running = false;
wait();
}
void issue(const QString &code) {
_lock.lock();
_commands.enqueue(code);
_lock.unlock();
_CommandQueued.wakeOne();
}
bool isCommandQueueEmpty() {
QMutexLocker lock(&_lock);
return _commands.isEmpty();
}
protected:
QString dequeue() {
QMutexLocker lock(&_lock);
QString cmd( _commands.dequeue() );
return cmd.isEmpty() ? "\n" : cmd;
}
void run() {
QMutex signal;
PyGILState_STATE state;
while(_running) {
// wait to be signaled ...
signal.lock();
_CommandQueued.wait(&signal,1);
signal.unlock();
if ( isCommandQueueEmpty() ) {
continue;
}
while ( !isCommandQueueEmpty() ) {
PythonQtObjectPtr p;
PyObject* dict = NULL;
state = PyGILState_Ensure();
if (PyModule_Check(_context)) {
dict = PyModule_GetDict(_context);
} else if (PyDict_Check(_context)) {
dict = _context;
}
if (dict) {
// this command blocks until the code has completed execution
emit python_busy(true);
p.setNewRef(PyRun_String(dequeue().toLatin1().data(), Py_single_input, dict, dict));
emit python_busy(false);
}
// error in the kernel
if (!p) {
PythonQt::self()->handleError();
}
PyGILState_Release(state);
}
}
}
PythonQtObjectPtr _context;
QMutex _lock;
QQueue<QString> _commands;
QWaitCondition _CommandQueued;
bool _running;
signals:
void python_busy(bool);
};
#endif //THREADEDPYTHONCONTEXT_H

Related

QThread: Destroyed while thread is still running in QTest

I have written a small multithreaded message queue. Now I am trying to do a test. But I am having a synchronization problem that I am not able to fix.
If I remove everything about the queue, the minimum verifiable example looks like this (sorry, it's a bit big):
#include <QCoreApplication>
#include <QDebug>
#include <QTimer>
#include <QtTest/QtTest>
#include <random>
#include <thread>
static std::vector< int > dummy;
class Writer : public QObject {
Q_OBJECT
public:
Writer( QObject *parent = nullptr ) : QObject( parent ) { }
Writer( unsigned, QObject *parent = nullptr ) : QObject( parent ) { }
public:
const std::vector< int > &beginPendings( ) { return dummy; }
void endPendings( ) { }
Q_SIGNALS:
void haveEvents( );
public Q_SLOTS:
void start( ) {
m_stop.test_and_set( );
connect( &m_inputTimer, &QTimer::timeout, this, &Writer::onTimer );
m_inputTimer.start( 100U );
connect( &m_outputTimer, &QTimer::timeout, this, &Writer::notifyEvents );
m_outputTimer.start( 250U );
}
void stop( ) {
m_inputTimer.stop( );
m_outputTimer.stop( );
}
private Q_SLOTS:
void onTimer( ) {
int limit = dist( mt );
for( int idx = 0; idx < limit; ++idx ) {
++m_idx;
}
}
void notifyEvents( ) {
emit haveEvents( );
}
private:
QTimer m_inputTimer;
QTimer m_outputTimer;
int m_idx = 0;
std::atomic_flag m_stop = ATOMIC_FLAG_INIT;
std::random_device rd;
std::mt19937 mt{ rd( ) };
std::uniform_int_distribution< int > dist{ 1, 20 };
};
class InOutQueueTest: public QObject {
Q_OBJECT
public Q_SLOTS:
void onPendingEvents( void ) {
writer->endPendings( );
}
void onTimeout( ) {
writer->stop( );
backendThread->exit( 0 );
backendThread->deleteLater( );
stop = true;
}
private Q_SLOTS:
void limit15( ) {
finishTimer.setSingleShot( true );
finishTimer.start( 5000 );
backendThread = new QThread( );
writer = new Writer( 15U );
connect( &finishTimer, &QTimer::timeout, this, &InOutQueueTest::onTimeout );
connect( writer, &Writer::haveEvents, this, &InOutQueueTest::onPendingEvents );
writer->moveToThread( backendThread );
backendThread->start( );
writer->start( );
while( !stop ) {
QCoreApplication::processEvents( );
}
}
private:
Writer *writer;
QThread *backendThread;
int last = 0;
QTimer finishTimer;
bool stop = false;
};
QTEST_GUILESS_MAIN( InOutQueueTest )
#include "inoutqueue.moc"
I hope the test lasts 5 seconds, and ends correctly. However, I get:
WARNING: InOutQueueTest::limit15() Generate 19 numbers, starting at 517
Loc: [/home/juanjo/Trabajos/qml/test/inoutqueue.cpp(53)]
WARNING: InOutQueueTest::limit15() Generate 19 numbers, starting at 536
Loc: [/home/juanjo/Trabajos/qml/test/inoutqueue.cpp(53)]
QFATAL : InOutQueueTest::limit15() QThread: Destroyed while thread is still running
FAIL! : InOutQueueTest::limit15() Received a fatal error.
Loc: [Unknown file(0)]
Totals: 1 passed, 1 failed, 0 skipped, 0 blacklisted, 5068ms
********* Finished testing of InOutQueueTest *********
Aborted
The code that should end the test (after 5 seconds) is this:
void onTimeout( ) {
writer->stop( );
backendThread->exit( 0 );
backendThread->deleteLater( );
stop = true;
}
I call the stop( ) method in Writer, call the exit( ) method in the auxiliary thread, and delete it in the next iteration of the event loop (it's the theory).
Too, in the Writer class, the stop( ) method is:
void stop( ) {
m_inputTimer.stop( );
m_outputTimer.stop( );
}
I simply do stop both timers.
What am I doing wrong ?
How do I solve it ?
I have written a small multithreaded message queue
Why? Qt inherently has one already... Post QEvents to QObjects - it's done in a thread-safe manner, with support for event priorities, automatic draining when receivers are deleted, etc. There's even some support for custom allocators for QEvent, so you could use a dedicated memory pool if you wanted to. Of course a dedicated queue may be faster, but that requires benchmarks and some requirement for which Qt's own queue's performance is insufficient. Multithreaded message queues have pesky corner cases as the receivers traverse threads, etc. - there's a reason why Qt's event queue code is less than straightforward. It's not far fetched to imagine that eventually you'd be reimplementing all of it, so there better be a good reason :)
First, let's note that the includes can be much simpler - and there's never a need for the QtModule/QtInclude format - that only helps when the application build is misconfigured. Not doing that lets you know of the problem earlier in the build - otherwise it'd fail at link time. Thus:
#include <QtCore>
#include <QtTest>
The slots that only emit a signal are unnecessary: signals are invokable, and you can connect anything invokable to signals directly - in Qt 4 syntax. In modern Qt syntax, slots aren't really necessary unless you need them for metadata (e.g. as used by the QtTest to detect test implementations). Otherwise, connect signals to any method whatsoever, even in non-QObjects, or to a functor (e.g. a lambda).
Now the serious problems:
The timers can only be manipulated from the thread they are in.
Move the timers to the same thread their user object is in. This is best done
by letting the parent object own the timers - the moving then happens automatically. Note that QObject ownership in no way clashes with retaining the timers by value - there'll be no double deletion, since by the time the parent QObject begins to delete the children, the timers are long gone.
Assert that the methods that manipulate the timers are called from the proper thread.
Optionally provide convenience to allow propagating the calls across the thread barriers.
You were re-connecting the timers to their slots each time the writer was started. That's never correct. Such connections should be made according to the scope of the objects involved, ensuring that they only happen once. In this case, since the timers live as long as the enclosing object, the connections belong in the constructor.
#include <random>
#include <vector>
class Writer : public QObject {
Q_OBJECT
static constexpr bool allowCrossThreadConvenience = false;
bool invokedAcrossThreads(auto method) {
bool crossThreadCall = QThread::currentThread() == thread();
if (crossThreadCall && allowCrossThreadConvenience) {
QMetaObject::invokeMethod(this, method);
return true;
}
Q_ASSERT(!crossThreadCall);
return false;
}
public:
Writer(QObject *parent = nullptr) : QObject(parent) {
connect(&m_inputTimer, &QTimer::timeout, this, &Writer::onTimer);
connect(&m_outputTimer, &QTimer::timeout, this, &Writer::haveEvents);
}
const auto &beginPendings() {
static std::vector<int> dummy;
return dummy;
}
void endPendings() { }
Q_SIGNAL void haveEvents();
Q_SLOT void start() {
if (invokedAcrossThreads(&Writer::start)) return;
m_outputTimer.start(250);
m_inputTimer.start(100);
}
Q_SLOT void stop() {
if (invokedAcrossThreads(&Writer::stop)) return;
m_inputTimer.stop();
m_outputTimer.stop();
}
private:
void onTimer() {
m_idx += dist(mt);
}
QTimer m_inputTimer{this};
QTimer m_outputTimer{this};
int m_idx = 0;
std::mt19937 mt{std::random_device()};
std::uniform_int_distribution<int> dist{1, 20};
};
Ssince this is C++, a thread class that's not destructible is a wee bit lame. Qt has kept QThread unchanged in that regard since it'd potentially break things (not really, but they'd rather error on the safe side given their enormous deployed base).
class Thread final : public QThread {
public:
using QThread::QThread;
~Thread() override {
requestInterruption();
quit();
wait();
}
};
The Thread can be safely destroyed at any time, and thus you can hold it by value. Also, foo(void) is a C-ism, unnecessary in C++ (it's just noise and unidiomatic since foo() is not foo(...) like it was in C). Now things become rather simple:
class InOutQueueTest: public QObject {
Q_OBJECT
Q_SLOT void limit15() {
Writer writer;
Thread thread; // must be last, after all the objects that live in it
connect(&writer, &Writer::haveEvents, &writer, &Writer::endPendings);
writer.start(); // now because we don't allow calling it from the wrong thread
writer.moveToThread(&thread);
QEventLoop eventLoop;
QTimer::singleShot(5000, &writer, [&]{
// This runs in the context of the writer, i.e. in its thread
writer.stop();
writer.moveToThread(eventloop.thread()); // needed to avoid a silly runtime warning
eventLoop.exit();
});
eventLoop.exec();
}
};
QTEST_GUILESS_MAIN( InOutQueueTest )
#include "inoutqueue.moc"
You need to always wait() on a thread before deleting it (in non-Qt speak "join").
Calling exit() on a QThread returns immediately and does not wait. And deleteLater() is performed in the caller's thread (not target thread), so you cannot count on it to be called "late enough".
Do exit(), then wait(), then deleteLater().

How can I communicate back the result from a std::thread to the Gui main thread in Qt?

In order to learn about threading in Qt and C++ I am creating a small example program.
It has a Gui with a button and a text field:
When the user presses the Calculate button it calculates pi using a sum formula.
In order for the Gui to be responsive during this lengthy operation the calculation will be performed in a separate thread.
First I created a subclass of QThread that does the calculation in its run() method and emits the signal void resultReady(double value); when it is finished.
This signal I connected to the slot void setResult(double value); in my Dialog Gui class.
This approach works fine.
Now I want to do the same thing using std::thread. How do I do this?
I am having problems communicating the result back to the Gui. I tried this:
class StdThreadStrategy : public QObject {
public:
void doTheWork() {
double pi = pi_sum();
QTimer::singleShot(0, this, [=] { dialog->setResult(pi); });
}
// This is called by Dialog when the user presses the Calculate button:
void calculatePi(Dialog* dialog) {
this->dialog = dialog;
std::thread t(&StdThreadStrategy::doTheWork, this);
thread = std::move(t);
}
private:
Dialog* dialog;
std::thread thread;
};
A StdThreadStrategy object is constructed in the constructor of Dialog:
Dialog::Dialog() : QDialog() {
// .. create gui code
calculatePiStrategy = new StdThreadStrategy();
}
// this is the slot I want called from the other thread:
void Dialog::setResult(double value) {
piLineEdit->setText(QString::number(value));
}
// Called by Calculate button:
void Dialog::calculate() {
calculatePiStrategy->calculatePi(this);
}
I was hoping using QTimer::singleShot in the doTheWork() method would allow me to post to the event queue of the Gui from another thread.
Unfortunately I get the error message: QObject::startTimer: Timers can only be used with threads started with QThread.
How can I communicate back the result from a std::thread to the Gui main thread in Qt?
Add a signal to your instance of StdThreadStrategy, and connect that via an explicitly deferred connection to the handler living in the UI thread. That way, you can safely call the signal from any thread, Qt takes care of sending it where it should go.
Also don't forget to join() your thread in the destructor of StdThreadStrategy. You also need to be aware that recycling a single instance like that is going to end up in race conditions. Just go and try what happens when you click the button again before pi had been fully computed.
There is no general answer to this kind of design problems. I give you just some tips here to show that c++11 provides a higher level of abstraction that can ease the manipulation of thread lifetime.
In your main GUI thread, run the async task (here I use std::async what gives you a std::future for further manipulation)
auto fut = std::async(std::launch::async, [=]() {
// do some work
});
Now, your UI is alive, run a Qtimer in the main thread with a callback that will check for the async procedure.
// callback content will be something like this
// checking via the future the state of the async task
if (fut.wait_for(std::chrono::milliseconds(25)) !=
std::future_status::ready) {
// not yet finished
return;
}
// No do what you want with the result
auto res = fut.get();
// emit a signal to refresh the gui etc.
Regards.
You could send a custom QEvent that carries the result from the worker thread to the thread your QObject lives in. See QEvent and QCoreApplication::postEvent()
Create your event class:
class MyEvent : public QEvent
{
public:
MyEvent(double result) : QEvent(QEvent::User), mResult(result) {
}
double result() {
return mResult;
}
private:
double mResult;
};
Post the event to the event loop and override the event() function to catch it:
class StdThreadStrategy : public QObject {
...
void doTheWork() {
double pi = pi_sum();
QCoreApplication::postEvent(this, new MyEvent(pi));
}
...
bool event(QEvent *event) override {
if (event->type() == QEvent::User) {
const auto result = static_cast<MyEvent*>(event)->result();
dialog->setResult(result);
}
return QObject::event(event);
}
...
}

Qt Thread with ping operation in Linux

I am trying to accomplish what looks like a very simple task... but it's being a nightmare instead.
I developed an app for a Linux Laptop. Inside the app, I would like to have an independent thread that continuously pings another PC (eg once every 5 seconds, forever... well, as long as the laptop is switched on).
Of course, when the PC that the app is pinging is not connected, the app has to work smoothly, without waiting for the ping operation to return... How can I achieve this?
At first I used a QTimer with QProcess:execute("ping"...), which works fine. The problem is that if the other PC doesn't reply, my whole app and its GUI freeze for about one second at each ping operation. Changing the "ping" options (setting "-i0.2", for example), in order to reduce waiting time for the ping operation, didn't help: when the other PC is not connected my app becomes very slow. If I remove the ping, of course everything works smoothly.
So, I decided to insert the "ping" operation in a QThread, but when I try to follow the second example in http://doc.qt.io/qt-4.8/qthread.html, nothing seems to work: the app doesn't even start.
Here's the code:
//Pinger.h
class Pinger : public QThread
{
Q_OBJECT
void run();
public:
void setParam(const QString &urlToPing); // it sets the url to ping
signals:
/// \brief Signal emitted when pinging of specified url fails
void pingFailed(int ok);
private:
QString pingurl;
};
//Pinger.cpp
void Pinger::run()
{
int exitCode;
QProcess pingProc;
while(true)
{
exitCode=pingProc.execute("ping",QStringList() << "-c 1" << "-i0.2" << pingurl);
emit pingFailed(exitCode);
sleep(5);
}
}
// MainWindow::MainWindow
pinga= new Pinger(); // defined in mainwindow.h as Pinger* Pinga
pinga->setParam(ip_address);
connect(pinga,SIGNAL(pingFailed(int)),this,SLOT(connectionLost(int)));
connect(pinga,SIGNAL(finished()),pinga,SLOT(deleteLater()));
pinga->start();
Has anyone tried anything similar? I am quite new to Qt, but this operation seems so trivial that I find it incredible that there's no clear way to implement it. so I hope I am just missing something obvious.
If QThread is used it is better to avoid sleep(5); and the loop while(true), since the thread cannot be closed gracefully without killing it. Instead of the loop and blocking sleep it is better to call that periodic task again by single shot timer initiated when the previous task (process execution) is finished. However, in that case that logic should be implemented in some other member slot (Pinger::doWork()). The slot run() should be kept with its default implementation that executes the tread event loop. The work can be started by connecting the QThread::started() signal with Pinger::doWork():
connect(pinga, SIGNAL(started()), pinga, SLOT(doWork()));
It is needed to be careful with QThread deletion. In general it is not good to delete QThread object by itself (calling deleteLater() from its finished() signal). It is better to stop the thread and to delete it in MainWindow destructor:
MainWindow::~MainWindow
{
// stop the even loop
pinga->quit();
// wait for finishing current thread task; it can work only
// if the thread is not blocked by while(true) with sleep
pinga->wait();
// delete if it is not a smart pointer
delete pinga;
}
It is also possible to use QProcess with its non-blocking API in the main GUI thread without QThread. In that case it should be started by QProcess::start() and the slots connected to the signals QProcess::error() and QProcess::finished() should be used to start the next iteration. Those slots also should not block the main thread, so the next ping should be started using QTimer once previous ping is finished.
Here is an example of the "Qt Way" to write your Pinger class. Note that no threads are needed. QProcess is used asynchronously, and reports its status through a Qt signal. Once you really grok Qt, you'll realize that using threads is very rarely the right or most natural solution to these types of problems.
Note that I'm using Qt 5 with C++11 support enabled to connect Qt signals to C++11 lambdas... you could just as easily write it in Qt4 style but it wouldn't be as compact and readable.
class Pinger : public QObject
{
Q_OBJECT
public:
Pinger(QObject *parent = 0) : QObject(parent)
{
//Have to do this ugliness because QProcess::finished is overloaded
auto finishedFunc = static_cast<void(QProcess::*)(int)>(&QProcess::finished);
connect(&m_process, finishedFunc, [this](int exitCode)
{
if( exitCode == 0 )
{
emit pingSuccess();
}
else
{
emit pingFailed(exitCode);
}
});
}
void run(const QString& hostToPing, int intervalInSeconds)
{
m_host = hostToPing;
QTimer* timer = new QTimer(this);
timer->start(intervalInSeconds * 1000);
QObject::connect(timer, &QTimer::timeout, [this]()
{
if ( m_process.state() == QProcess::NotRunning )
{
m_process.start(QString("ping -c 1 -W 1 %1").arg(m_host));
}
else
{
qDebug() << "Cannot ping, previous ping operation still in progress!";
}
});
}
signals:
void pingSuccess();
void pingFailed(int exitCode);
private:
QProcess m_process;
QString m_host;
};
Using it is as simple as:
Pinger pinger;
QObject::connect(&pinger, &Pinger::pingSuccess, []()
{
qDebug() << "Host is up!";
});
QObject::connect(&pinger, &Pinger::pingFailed, [](int exitCode)
{
qDebug() << "Host is unreachable! Ping exit code = " << exitCode;
});
pinger.run("google.com", 3);
I had the same problem and fixed it by running the ping command in an own thread. By using a signal, I'm interacting with the non-blocking GUI.
1) I've declared a Ping class, which run the Ping command:
class Ping {
public:
static bool start(QString host) {
QStringList parameters;
#if defined(WIN32)
parameters << "-n" << "1";
#else
parameters << "-c 1";
#endif
parameters << host;
int exitCode = QProcess::execute("ping", parameters);
if (exitCode==0) {
return true;
} else {
return false;
}
}
};
2.) Additionally I've a NetworkReceiver class, which creates the Network Thread via a Slot (startConnectionCheck) and interacts with the GUI via a Signal (newConnectionStatus):
class NetworkReceiver : public QObject
{
Q_OBJECT
public:
explicit NetworkReceiver(QObject * parent = nullptr);
~NetworkReceiver();
void start() {
while(true) {
emit newConnectionStatus(Ping::start("google.at"));
QThread::sleep(5);
}
}
signals:
void newConnectionStatus(bool connected);
public slots:
void startConnectionCheck() {
QFuture<void> test = QtConcurrent::run(this, &NetworkReceiver::start);
}
};

Event Loop in Qt-based DLL in a non-Qt application

I was searching the whole web for an answer but didn't find the solution for my problem. Or maybe I did but because I am a beginner to C++/programming/Qt I didn't understand them.
The closest thing was a question here Using a Qt-based DLL in a non-Qt application. I tried to use this method but so far unsuccessfully.
I try to create a DLL, it's the API for our USB device. The library should work on non-Qt applications too. I have PIMPL-ed all Qt stuff and private classes so the code below is one layer under the public classes. I am using QSerialPort and a lot of SIGNAL/SLOT so I need the QCoreApplications event loop. The ReaderSerial is where Qt stuff begins it also instantiate another class where the QSerialPort running in a different QThread.
At this moment my problem is the whole thing crashes on error: “QTimer can only be used with threads started with QThread”
I guess my Qt-based Classes like ReaderSerial don't "see" the QCoreApp event loop or something like that. So my question is how to provide the QCoreApplication event loop to my DLL so all Qt-based classes I created will work and I will be able to call methods from my DLL.
Thank you very much for answers.
reader_p.h
class ReaderPrivate
{
public:
ReaderPrivate();
~ReaderPrivate();
void static qCoreAppExec();
ReaderSerial *readerSerial;
void connectReader(std::string comPort);
void disconnectReader();
};
reader.cpp
// Private Qt application
namespace QAppPriv
{
static int argc = 1;
static char * argv[] = {"API.app", NULL};
static QCoreApplication * pApp = NULL;
};
ReaderPrivate::ReaderPrivate()
{
std::thread qCoreAppThread(qCoreAppExec);
qCoreAppThread.detach();
readerSerial = new ReaderSerial;
}
ReaderPrivate::~ReaderPrivate()
{
delete readerSerial;
}
void ReaderPrivate::qCoreAppExec()
{
if (QCoreApplication::instance() == NULL)
{
QAppPriv::pApp = new QCoreApplication(QAppPriv::argc, QAppPriv::argv);
QAppPriv::pApp->exec();
if (QAppPriv::pApp)
delete QAppPriv::pApp;
}
}
void ReaderPrivate::connectReader(std::string comPort)
{
readerSerial->openDevice(comPort);
}
void ReaderPrivate::disconnectReader()
{
readerSerial->closeDevice();
}
Based on #Kuba Ober answer I created a shared library. It took me some time to understand what's going on and how to make it work, but it still doesn't do what it should. So I am now asking for advice how to make this code work.
apic.h
#include "Windows.h"
extern "C"
{
__declspec(dllexport) void WINAPI kyleHello();
}
apic.cpp
#include "apic.h"
#include "appthread.h"
void WINAPI kyleHello()
{
worker->hello();
}
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID)
{
static AppThread *thread;
switch (reason)
{
case DLL_PROCESS_ATTACH:
thread = new AppThread;
thread->start();
break;
case DLL_PROCESS_DETACH:
delete thread;
break;
default:
break;
}
return TRUE;
};
appthread.h
#include <QThread>
#include <QCoreApplication>
#include <QPointer>
#include "worker.h"
static QPointer<Worker> worker;
class AppThread : public QThread
{
public:
AppThread();
~AppThread();
// No need for the Q_OBJECT
QPointer<QCoreApplication> m_app;
void run() Q_DECL_OVERRIDE
{
std::cout << "\n AppThread::run";
int argc;
char *argv;
QCoreApplication app(argc, &argv);
m_app = &app;
std::cout << "\nAppThread::run before Worker";
Worker worker_;
worker = &worker_;
std::cout << "\nAppThread::run before app.exec";
app.exec();
}
//using QThread::wait(); // This wouldn't work here.
};
appthread.cpp
#include "appthread.h"
AppThread::AppThread()
{
std::cout << "\n AppThread::ctor";
}
AppThread::~AppThread()
{
std::cout << "\n AppThread::dtor \n";
m_app->quit();
wait();
}
worker.h
#include <QObject>
#include <QDebug>
#include <iostream>
class Worker : public QObject
{
Q_OBJECT
Q_INVOKABLE void helloImpl()
{
std::cout << "I'm alive.";
//qDebug() << "I'm alive.";
}
public:
Worker();
void hello();
};
worker.cpp
#include "worker.h"
Worker::Worker()
{
std::cout << "\nWorker::ctor";
hello();
}
void Worker::hello()
{
std::cout << "\nWorker::hello()";
// This is thread-safe, the method is invoked from the event loop
QMetaObject::invokeMethod(this, "helloImpl", Qt::QueuedConnection);
}
The output from this is usually:
AppThread::ctor
Worker::hello()
AppThread::dtor
sometimes:
AppThread::ctor
Worker::hello()
AppThread::run
AppThread::dtor
sometimes:
AppThread::ctor
Worker::hello()
AppThread::dtor
QMutex: destroying locked mutex
GitHub repo: https://github.com/KyleHectic/apic.git
First of all, if you need QCoreApplication, it will always be your QCoreApplication. You should not attempt any sort of dynamic linking of Qt in your DLL, in case it would end up picking up Qt from the application that is your consumer. There are no guarantees of binary compatiblity between those Qt libraries - this would force your consumer to use the exact same compiler version, and a binary compatible build of Qt. That is, generally speaking, a fantasy.
So, the idea that you need to test for QCoreApplication's presence simply doesn't fit your use model. You will always need it. All you have to do is to fire up a thread and start the core application there. That's it.
QPointer<Worker> worker;
extern "C" {
__declspec(DLLEXPORT) WINAPI VOID kyleHello() {
worker->hello();
}
}
class Worker() : public Q_OBJECT {
Q_OBJECT
Q_INVOKABLE void helloImpl() { qDebug() << "I'm alive."; }
public:
void hello() {
// This is thread-safe, the method is invoked from the event loop
QMetaObject::invokeMethod(this, "helloImpl", Qt::QueuedConnection);
}
Worker() { hello(); }
};
class AppThread : public QThread {
// No need for the Q_OBJECT
QPointer<QCoreApplication> m_app;
void run() Q_DECL_OVERRIDE {
int argc;
char * argv;
QCoreApplication app(argc, &argv);
m_app = &app;
Worker worker_;
worker = &worker_;
app.exec();
}
using QThread::wait(); // This wouldn't work here.
public:
AppThread() {}
~AppThread() { m_app->quit(); wait(); }
}
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID) {
static AppThread * thread;
switch (reason) {
case DLL_PROCESS_ATTACH:
thread = new AppThread;
thread->start();
break;
case DLL_PROCESS_DETACH:
delete thread;
break;
default:
break;
}
return TRUE;
}
The API exposed to your consumer comes in several kinds:
Write-only APIs that don't wait for a result. Internally you simply post an event to any of your QObjects. You can also use QMetaObject::invokeMethod with a Qt::QueuedConnection - it ends up simply posting a QMetaCallEvent to the target object. Events can be posted to any QObject from any thread, non-QThread-started-threads included.
Foreign-thread callbacks: Dedicate a separate thread in which the consumer-provided callbacks execute. They'd be invoked by one or more QObjects living in that thread.
Client-thread callbacks: Use platform-specific asynchronous procedure calls that execute a callback in the context of any thread - typically the thread where the callback registration function was called from. Those callbacks execute when the thread is in an alertable state.
If you wish to limit yourself to a subset of alertable states where the message pump is running (GetMessage is called), you can create a message-only, invisible window, post messages to it, and issue the consumer callbacks from the window's callback function. If you're clever about it, you can pass QEvent pointers via those messages and pass them to QObject::event in the callback. That's how you can make a QObject effectively live in a thread with a native event loop and no Qt event loop running.
Blocking APIs that effectively synchronize the calling thread to your thread: use QMetaObject::invokeMethod with Qt::BlockingQueuedConnection. The caller will wait until the slot finishes executing in the receiving thread, optionally passing a result back.
Blocking APIs that use fine-grained locking. Those also synchronize the caller thread to your thread, but only at the level of locking certain data structures. Those are useful mainly to read parameters or extract data - when the overhead of going through the event loop would dwarf the small amount of work you perform.
What APIs you offer depends on the design criteria for your API.
All the APIs must be extern C and must not use C++. You can only offer C++ APIs if you plan on building the DLL using multiple VS versions (say 2008, 2010, 2012, 2013) - even then you must not expose Qt to the consumer, since the consumer may still use a binary incompatible version.
QtWinMigrate solves the Qt in Win32 or MFC event loop problem. One of the answers to the question you reference mentions this.
For a Qt DLL that needs to link up the event loop in DllMain, simply use QMfcApp::pluginInstance

How to Stop a QThread That Runs a Blocking Forever Loop?

I have some rough code that I've been experimenting with:
someserver.cpp (a GUI)
#include "server.h"
#include "ui_server.h"
Server::Server(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Server)
{
ui->setupUi(this);
}
Server::~Server()
{
delete ui;
}
void Server::onBtnStartClicked()
{
QThread worker;
worker.start(); // Start worker thread that goes into an infinite loop with a blocking call
}
void Server::onBtnExitClicked()
{
// How do I cleanly stop worker from running?
QApplication::quit();
}
worker.cpp
#include "worker.h"
Worker::Worker(QObject *parent) :
QThread(parent)
{
}
void Worker::run()
{
for (;;)
{
// a blocking IO call here like pipe, or msgrcv
// process data received
}
}
Since the worker thread runs in a forever loop with a blocking IO call, how will I be able to structure this so that when the Stop button is pressed in the GUI thread, the worker thread is stopped cleanly?
You could of course put a boolean value within the for loop in Worker::run() checked every iteration, which breaks on ==true and is set by the gui Stop button. Of course, this won't quit the thread while execution is blocked.
Probably better is to get rid of the for loop and use Qt's signals and slots to setup a callback function, connected to a signal like QIODevice::readyRead(). These will be called only when there is information available in the socket/pipe whatever. Any other time you'll be able to quit the thread with QThread::exit(). You'll need to call QThread::exec() at some point as well to get the event loop going.
in infinity loop paste this code and enjoy...
QTime dieTime = QTime::currentTime().addMSecs(1);
while( QTime::currentTime() < dieTime ) {
QCoreApplication::processEvents( QEventLoop::AllEvents, 1);
}
don't forget
#include <QCoreApplication>
#include <QTime>
see you
To stop the worker thread it is necessary to add "stop requested" boolean flag, which should be tested at the beginning of each iteration. Also the synchronization is needed to read/write value of this boolean flag.
Here is the draft version:
class Worker : public QThread {
public:
Worker() : stopRequested(false) {}
void requestStop()
{
QMutexLocker locker(&mutex);
stopRequested = true;
}
void run()
{
forever
{
if (stopRequested())
break;
// a blocking IO call here like pipe, or msgrcv
// process data received
}
}
private:
bool stopRequested()
{
QMutexLocker locker(&mutex);
return stopRequested;
}
QMutex mutex;
bool stopRequested;
};
First of all, you should set the parent for Worker to make it a child of another QObject, to clean it right way when the app is done, and create it on heap. i.e. dynamic way .
Second, simplest way to do what you want is to define slot which will set boolean member of Worker object and check it in each cycle to break endless loop. Don't forget to connect this slot to a right signal.
so you can put in constructor of the Server along the lines
QThread * worker = new QThread (this);
connect (this, SIGNAL(terminator()), worker, SLOT(terminate()));
in Server class declaration:
signals:
terminator();
in class Worker :
private:
bool terminate_; // don't forget initialize it to false
public slots:
void terminate(){terminate_ = true;}
and in the cycle:
if (terminate_) {/* .. do exit things...*/; return;
after that emit signal terminator() from server whenever you need.
If you will need more complicated management then simple stop, you will probably need to protect your state variable with a mutex.
Here you have the explanation of you're problem, i think. When your application will end, you should do something like this :
MyClass::~MyClass()
{
m_thread->requestStop();
m_thread->wait(); // Force the thread trying to destroy
// an object of type MyClass, to wait
// the end of the execution of m_thread
delete m_thread;
}
wait() is the solution for your synchronisation problem. You could also change requestStop() to :
void requestStop()
{
mutex.lock();
stopRequested = true;
mutex.unlock();
wait();
}
Removing QMutexLocker is important to avoid a Deadlock situation.