C++ Builder: interface that was marshalled for a different thread - c++

In order to use a COM object from a thread, I inserted CoInitialize(NULL) into the thread Execute function and CoUninitialize() into the Terminate function.
Everything works fine, except if the user aborts the thread by calling the Terminate function from the calling form.
It seems that the Terminate function called by a form is considered as another thread (Error message: 'The application called an interface that was marshalled for a different thread').
On the other hand I cannot put the code into a specific function to call by using Synchronize. This way makes the program still until the COM process of called function ends.
I know that functions to readdress the COM marshaling exist. But don't know exactly what to do. I did not find examples in C++, too.
Before asking help, I tried various ways to overcome the problem. Unfortunately I am here.
Here is my code:
class TThreadCamera : public TThread
{
private:
Variant Camera;
protected:
void __fastcall Execute();
public:
void __fastcall Terminate(TObject *Sender);
public:
__fastcall TThreadCamera();
};
-
__fastcall TThreadCamera::TThreadCamera()
: TThread(false)
{
}
//---------------------------------------------------------------------------
void __fastcall TThreadCamera::Execute()
{
FreeOnTerminate = true;
OnTerminate = &Terminate;
CoInitialize(NULL);
Camera = Variant::CreateObject("ASCOM.Simulator.Camera");
Camera.OlePropertySet("Connected", true);
Camera.OleProcedure("StartExposure", 60, true);
while ((! (bool) Camera.OlePropertyGet("ImageReady")))
Sleep 100;
}
//---------------------------------------------------------------------------
void __fastcall TThreadCamera::Terminate(TObject *Sender)
{
if (Camera.OlePropertyGet("CameraState") == 2) // Exposure currently in progress
Camera.OleProcedure("AbortExposure");
CoUninitialize();
}
//---------------------------------------------------------------------------

You need to call CoInitialize and CoUninitialize on the same thread, since they act on the calling thread. The OnTerminate event is always executed on the main thread.
So, remove your OnTerminate event handler, move that code into the thread, and so call CoUninitialize from the thread:
void __fastcall TThreadCamera::Execute()
{
FreeOnTerminate = true;
CoInitialize(NULL);
Camera = Variant::CreateObject("ASCOM.Simulator.Camera");
// code to operate on the camera goes here
CoUninitialize();
}
It would probably be prudent to protect the uninitialization inside a finally block.

In Delphi, if you need to call a thread termination code in the thread context, you should override the protected TThread.DoTerminate method instead of writing OnTerminate event handler.

The TThread.OnTerminate event is called in the context of the main UI thread. The virtual TThread.DoSynchronize() method, which the worker thread calls after Execute() exits, uses TThread.Synchronize() to call OnTerminate. DoTerminate() is always called, even if Execute() exits due to an uncaught exception, so overriding DoTerminate() is a good way to perform thread-specific cleanup.
CoInitialize() and CoUninitialize() must be called in the same thread. So, you must call CoUninitialize() inside of Execute(), or override DoTerminate(). I prefer the latter, as it reduces the need for using try/catch or try/__finally blocks in Execute() (an RAII solution, such as TInitOle in utilscls.h, is even better).
An apartment-threaded COM object can only be accessed in the context of the thread that creates it. So you must call the camera's CameraStateproperty and AbortExposure() procedure inside of Execute(), or override DoTerminate(), as well.
The TThread.Terminate() method simply sets the TThread.Terminated property to true, it does nothing else. It is the responsibility of Execute() to check the Terminated property periodically and exit as soon as possible. Your while that waits for the camera's ImageReady property to be true can, and should, check the thread's Terminated property so it can stop waiting when requested.
Try something more like this:
class TThreadCamera : public TThread
{
private:
bool init;
protected:
void __fastcall Execute();
void __fastcall DoTerminate();
public:
__fastcall TThreadCamera();
};
__fastcall TThreadCamera::TThreadCamera()
: TThread(false)
{
FreeOnTerminate = true;
}
void __fastcall TThreadCamera::Execute()
{
init = SUCCEEDED(CoInitialize(NULL));
if (!init) return;
Variant Camera = Variant::CreateObject("ASCOM.Simulator.Camera");
Camera.OlePropertySet("Connected", true);
Camera.OleProcedure("StartExposure", 60, true);
while (!Terminated)
{
if ((bool) Camera.OlePropertyGet("ImageReady"))
return;
Sleep(100);
}
if (Camera.OlePropertyGet("CameraState") == 2) // Exposure currently in progress
Camera.OleProcedure("AbortExposure");
}
void __fastcall TThreadCamera::DoTerminate()
{
if (init) CoUninitialize();
TThread::DoTerminated();
}
Or:
class TThreadCamera : public TThread
{
protected:
void __fastcall Execute();
public:
__fastcall TThreadCamera();
};
#include <utilcls.h>
__fastcall TThreadCamera::TThreadCamera()
: TThread(false)
{
FreeOnTerminate = true;
}
void __fastcall TThreadCamera::Execute()
{
TInitOle oleInit;
Variant Camera = Variant::CreateObject("ASCOM.Simulator.Camera");
Camera.OlePropertySet("Connected", true);
Camera.OleProcedure("StartExposure", 60, true);
while (!Terminated)
{
if ((bool) Camera.OlePropertyGet("ImageReady"))
return;
Sleep(100);
}
if (Camera.OlePropertyGet("CameraState") == 2) // Exposure currently in progress
Camera.OleProcedure("AbortExposure");
}

Related

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);
}
...
}

Calling `QQuickPaintedItem::updateImage(const QImage& image)` in a thread safe way (no QThread)

I'm reading this answer about creating a custom QQuickPaintedItem in C++ How to paint sequential image in efficient way in QQuickPaintedItem
and I want to write code that is not Qt-dependent. That is, I don't want to rely on QThread. I just want to call CameraView::updateImage(const QImage& image) from a std::thread, not q QThread. Is it possible?
I thougth of simply creating a thread, passing the CameraView instance to it, and calling it from the thread. However, this is not thread safe.
How can I call CameraView::updateImage(const QImage& image) in a thread safe manner?
You can, of course, use the C++ Standard Library classes in your code. For example, use std::mutex to update image as follows:
void CameraView::updateImage(const QImage& image) {
std::unique_lock<std::mutex> lock(mutex); // std::mutex object is located elsewhere
// ... the rest of the code as before ...
}
You can also leave CameraView code unchanged and call the updateImage function from external code. Just make sure that the image is updated using the same mutex in all threads:
void functionInAnotherThread(CameraView& cameraView) {
std::unique_lock<std::mutex> lock(mutex); // std::mutex object is located elsewhere
// ... the rest of the code ...
cameraView.updateImage(image);
// ... the rest of the code ...
}
Let's try to implement this approach. Let's change the header file a bit:
class CameraView : public QQuickPaintedItem {
Q_OBJECT
Q_DISABLE_COPY(CameraView)
public:
CameraView(QQuickItem* parent = nullptr);
public slots:
void updateImage(const QImage&);
void scheduleUpdate();
protected:
QImage image_;
};
Now, write the definitions of the methods:
void CameraView::updateImage(const QImage& image) {
image_ = image.copy(); // Does deep copy of image data.
}
void CameraView::scheduleUpdate() {
update();
}
void CameraView::paint(QPainter* painter) {
painter->drawImage(this->boundingRect(), image_);
}
Finally, we write the function of updating the picture and scheduling redrawing:
void functionInAnotherThread(CameraView& cameraView) {
std::unique_lock<std::mutex> lock(mutex); // std::mutex object is located elsewhere
cameraView.updateImage(image);
lock.unlock(); // Unlock the mutex as we have already updated the image.
QMetaObject::invokeMethod(&cameraView, "scheduleUpdate",
Qt::QueuedConnection); // Call slot through the queued connection.
}
With Qt::QueuedConnection, the slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread. Thus, we can schedule the widget to be redrawn from another thread. Try using other types of connections if this does not work.

Non locking calls via python console for PythonQt library

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

Why using QMetaObject::invokeMethod when executing method from thread

I have following code:
class A : public QObject
{
Q_OBJECT
public:
A() : QObject()
{
moveToThread(&t);
t.start();
}
~A()
{
t.quit();
t.wait();
}
void doSomething()
{
QMetaObject::invokeMethod(this,"doSomethingSlot");
}
public slots:
void doSomethingSlot()
{
//do something
emit ready();
}
signals:
void ready();
private:
QThread t;
}
The question why from doSomething it must be call via QMetaObject::invokeMethod. I know that there is something with connection type. Could some one explain what is under the hood?
As you haven't specified a Qt::ConnectionType, the method will be invoked as Qt::AutoConnection, which means that it will be invoked synchronously (like a normal function call) if the object's thread affinity is to the current thread, and asynchronously otherwise. "Asynchronously" means that a QEvent is constructed and pushed onto the message queue, and will be processed when the event loop reaches it.
The reason to use QMetaObject::invokeMethod if the recipient object might be in another thread is that attempting to call a slot directly on an object in another thread can lead to corruption or worse if it accesses or modifies non-thread-safe data.
I like this trick:
void A:doSomethingSlot()
{
if (thread()!=QThread::currentThread()) {
QMetaObject::invokeMethod(this,"doSomethingSlot", Qt::QueuedConnection);
return;
}
// this is done always in same thread
...
emit ready();
}

Is it possible to implement polling with QThread without subclassing it?

I have a class, which is an abstraction of some device.
class Device
{
public:
...
void Start();
void Stop();
void MsgLoop();
signals:
void sMsgArrived();
}
Start() and Stop() are called from GUI thread. Start() begins new thread, which runs MsgLoop(). It looks like this:
void MsgLoop()
{
forever {
if(SUCCESS == ReadMsg()) //synchronous, non-blocking
{
ProcessMsg(); //quite fast
emit sMsgArrived(); //this signal is connected with a slot in GUI thread
}
}
}
When Stop() is called, program should return from MsgLoop() and stop the thread. How can I implement this with QThread without subclassing it?
Generally you have to decide who will be responsible for managing the thread. Is it the Device or the main window? Or possibly some device manager. In your case the Device should probably manage its own thread, so if you don't want to subclass it, use composition:
class Device : QObject
{
Q_OBJECT
public:
Device(QObject * parent = NULL);
void Start();
void Stop();
private slots:
void MsgLoop();
signals:
void sMsgArrived();
private:
QThread thread;
bool stopThread;
};
Device::Device(QObject * parent) : QObject(parent)
{
moveToThread(&thread);
connect(&thread, SIGNAL(started()), this, SLOT(MsgLoop()));
}
void Device::Start()
{
stopThread = false;
thread.start();
}
void Device::Stop()
{
stopThread = true;
thread.wait(); // if you want synchronous stop
}
void Device::MsgLoop()
{
// your loop
while(!stopThread)
if(SUCCESS == ReadMsg())
{
ProcessMsg();
emit sMsgArrived();
}
QThread::currentThread->quit();
}
NOTE: the thread stopping will only work if ReadMsg really is non-blocking. If you later decide to switch to blocking read (and that would probably be appropriate for most cases), you will have to figure out another way how to stop your thread.
If you look at this link you can see that it is possible to run a method in a separate thread without subclassing a QThread.
However what you are asking is running a message loop forever.
If you follow the given example you can run your loop without subclassing but the QThread object will never enter into its own message loop cause it will never return from your slot. So here is an example but I think it would be a bad design
class Device : public QObject
{
Q_OBJECT
public:
Device(QObject* parent = 0);
~Device();
public Q_SLOTS:
void MsgLoop();
};
QThread* thread = new QThread;
Device* device = new Device;
void Widget::onBtnStartClicked()
{
device->moveToThread(thread);
//This will call start method of Device
connect(thread, SIGNAL(started()), device, SLOT(MsgLoop()));
//This will start the event loop of thread
thread->start();
}
void Widget::onBtnStopClicked()
{
//Tells the thread to exit
thread->exit(0);
}
I am afraid you have to subclass a QThread if you want to run a forever loop.
IMHO you shouldn't. Polling requires being in a forever loop. You must do this in QThread's run function so there is no way to re-implement a function without sub-classing first. Even if you were to try and workaround it with a single shot timer I don't recommend it. You are better off(this is how i like to do it) sub-classing QThread, calling moveToThread(), not call exec() and put a forever loop in run. For an example of this look at the Fortune Blocking Client example from qt. If you don't call moveToThread() on QThread then the QThread object still resides in the GUI main thread and they both share the same event loop (which is bad when using polling functions). Calling moveToThread(QThread) without calling exec() means the QThread will not have an event loop(which is good in your case). Calling exec() would start it's own event loop but is not used for polling schemes and you would leave the run function.