Have a simple Qt app. Gui thread, creates Dev thread it creates (in its run()) Read thread. Dev and Read threads are my classes inherited from QThread. The Read thread should read data from COM port continuously. An approximate view of Read run is following.
read::run()
{
sp2->clear();
while (DO_EXEC)
{
if (DO_WRITE)
{
// write data to port
}
usleep(500);
ba = sp2->bytesAvailable();
if (ba > 0)
{
int a = sp2->read(&BUF[BUF_END], ba);
// process data
emit sgnl(sendeddata);
}
}
}
To start it I emit signal in GUI that is passed to Dev at it is passed to the following read slot:
read::slot_readStart()
{
// some stuff
if (doStart && !isRunning())
{
sp2 = new QSerialPort(this);
sp2->setPortName("COM3");
sp2->setBaudRate(256000);
sp2->setDataBits(QSerialPort::Data8);
sp2->setStopBits(QSerialPort::OneStop);
sp2->setParity(QSerialPort::NoParity);
sp2->setFlowControl(QSerialPort::NoFlowControl);
sp2->setReadBufferSize(5000);
bool isOpen = sp2->open(QIODevice::ReadWrite);
DO_EXEC = true;
start();
}
}
This works. But, if I place creating and setup and opening serial port to run method, then the port is open, but the bytesAvailable() are always zero? Why it is possible?
Thank you in adcance.
I agree with Orest Hera, in that you are using a "non recommended" way of implementing threads.
You are using inheritance for your thread object.
It is important to understand how QThreads work. The general procedure to using the QThreads is:
Make Object to go into thread, assign no parent
Make thread
Move object into thead using obj->moveToThread(thread)
Connect a signal to a slot in the object that will instatiate the object members (if required)
Start the thread: thread->start()
For example:
MyObj *myObj = new MyObj(0); // 0 = no parent if your object inherits QObject
QThread* thread = new QThread;
myObj->moveToThread(thread);
QObject::connect(thread, SIGNAL(started()), myObj, SLOT(run()));
thread->start();
So your object can still have its "run()" function, but it won't be overloading anything.
Also your run() function does not need to be a "forever" loop, it is simply an initialization function (create the serial port or whatever). Then you add other slots for other events, e.g. you can connect the QSerialPort::readyRead() to your "incoming data slot" handler to handle any data received from the serial port.... and so on.
I think this will solve your issues. It is difficult to tell exactly why your serial port does not work in your overloaded "Run()" function because I can't see how you are calling /creating the thread (i.e. the rest of your code) or where DO_EXEC is initialized etc... There is probably some ordering of events or thread ownership issue here.
Note: I am not saying you can't inherit thread class, but if you do that it is so that you create your own custom thread class (to do thread stuff), but not some other class to create a hybrid of thread utility and other stuff. There is a fair amount of information relating to this here (on SO) and on the qt forum if you are interested in the why/how etc... :)
Related
I need to update a QGraphicsView with a QGraphicsScene from a thread.
Below is some pseudo'ish code example of what I am doing which is causing me issues (runtime errors).
What am I doing wrong, and how should I be doing it?
Main App:
void Main::startThread()
{
view = new QGraphicsView(...);
thread = new MyThread(...);
connect(thread, SIGNAL(doSceneUpdate(QGraphicsScene*)), this, SLOT(updateScene(QGraphicsScene*)));
thread->start();
}
void Main::updateScene(QGraphicsScene *scene)
{
view->SetScene(scene);
view->show();
repaint();
}
The Thread:
void MyThread::run()
{
QGraphicsScene *scene = new QGraphicsScene(...);
while(1)
{
//draw stuff on the scene
emit doSceneUpdate(scene);
//some delay
}
Thanks in advance!!!
[edit]
The error is:
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread
3e53c0. Receiver '' (of type 'QGraphicsScene') was created in thread 1476cd18", file c:\Qt\qt-everywhere-opensource-src-4.8.2\src\corelib\kernel\qcoreapplication.cpp, line 501
What am I doing wrong, and how should I be doing it?
I think the canonical answer is here -- in a nutshell, the article states that you shouldn't be subclassing QThread, but rather you should use a "bare" (i.e. not-subclassed) QThread object and connect its started() signal to a slot that will then be run in the context of that thread, after the thread starts. That way the object-thread-ownership issues are handled automatically for you.
Note also that threads other than the main Qt thread are generally not allowed to create or interact directly with GUI objects like QGraphicsScene, since doing that would introduce race conditions due to the operations going on simultaneously behind the scenes in Qt's GUI event loop. If you want to use a separate thread, you'll need to keep it away from your GUI objects, and instead just have it emit asynchronous signals and/or send Events to the main/GUI thread to get the main/GUI thread to do the GUI-object updates on its behalf.
The problem is with your connection line. You are connecting a slot to a signal which does not make sense. You should connect the signal from the thread to the slot :
connect(thread, SIGNAL(doSceneUpdate(QGraphicsScene*)),this, SLOT(updateScene(QGraphicsScene*)));
in
void MyThread::run()
{
QGraphicsScene *scene = new QGraphicsScene(...);
...
}
do you pass this to the constructor of QGraphicsScene()?
That could be one cause of error, since now you are passing a child of MyThread to Main
Try creating a QGraphicsScene object on the stack or with the parent as NULL ( new QGraphicsScene(0) )
(Pseudo-)Code
Here is a non-compilable code-sketch of the concepts I am having trouble with:
struct Data {};
struct A {};
struct B {};
struct C {};
/* and many many more...*/
template<typename T>
class Listener {
public:
Listener(MyObject* worker):worker(worker)
{ /* do some magic to register with RTI DDS */ };
public:
// This function is used ass a callback from RTI DDS, i.e. it will be
// called from other threads when new Data is available
void callBackFunction(Data d)
{
T t = extractFromData(d);
// Option 1: direct function call
// works somewhat, but shows "QObject::startTimer: timers cannot be started
// from another thread" at the console...
worker->doSomeWorkWithData(t); //
// Option 2: Use invokeMethod:
// seems to fail, as the macro expands including '"T"' and that type isn't
// registered with the QMetaType system...
// QMetaObject::invokeMethod(worker,"doSomeGraphicsWork",Qt::AutoConnection,
// Q_ARG(T, t)
// );
// Option 3: use signals slots
// fails as I can't make Listener, a template class, a QObject...
// emit workNeedsToBeDone(t);
}
private:
MyObject* worker;
T extractFromData(Data d){ return T(d);};
};
class MyObject : public QObject {
Q_OBJECT
public Q_SLOTS:
void doSomeWorkWithData(A a); // This one affects some QGraphicsItems.
void doSomeWorkWithData(B b){};
void doSomeWorkWithData(C c){};
public:
MyObject():QObject(nullptr){};
void init()
{
// listeners are not created in the constructor, but they should have the
// same thread affinity as the MyObject instance that creates them...
// (which in this example--and in my actual code--would be the main GUI
// thread...)
new Listener<A>(this);
new Listener<B>(this);
new Listener<C>(this);
};
};
main()
{
QApplication app;
/* plenty of stuff to set up RTI DDS and other things... */
auto myObject = new MyObject();
/* stuff resulting in the need to separate "construction" and "initialization" */
myObject.init();
return app.exec();
};
Some more details from the actual code:
The Listener in the example is a RTI DataReaderListener, the callback
function is onDataAvailable()
What I would like to accomplish
I am trying to write a little distributed program that uses RTI's Connext DDS for communication and Qt5 for the GUI stuff--however, I don't believe those details do matter much as the problem, as far as I understood it, boils down to the following:
I have a QObject-derived object myObject whose thread affinity might or might not be with the main GUI thread (but for simplicity, let's assume that is the case.)
I want that object to react to event's which happen in another, non-Qt 3rd-party library (in my example code above represented by the functions doSomeWorkWithData().
What I understand so far as to why this is problematic
Disclaimer: As usual, there is always more than one new thing one learns when starting a new project. For me, the new things here are/were RTI's Connext and (apparently) my first time where I myself have to deal with threads.
From reading about threading in Qt (1,2,3,4, and 5 ) it seems to me that
QObjects in general are not thread safe, i.e. I have to be a little careful about things
Using the right way of "communicating" with QObjects should allow me to avoid having to deal with mutexes etc myself, i.e. somebody else (Qt?) can take care of serializing access for me.
As a result from that, I can't simply have (random) calls to MyClass::doSomeWorkWithData() but I need to serialize that. One, presumably easy, way to do so is to post an event to the event queue myObject lives in which--when time is available--will trigger the execution of the desired method, MyClass::doSomeWorkWithData() in my case.
What I have tried to make things work
I have confirmed that myObject, when instantiated similarly as in the sample code above, is affiliated with the main GUI thread, i.e. myObject.thread() == QApplication::instance()->thread().
With that given, I have tried three options so far:
Option 1: Directly calling the function
This approach is based upon the fact that
- myObject lives in the GUI thread
- All the created listeners are also affiliated with the GUI thread as they are
created by `myObject' and inherit its thread that way
This actually results in the fact that doSomeWorkWithData() is executed. However,
some of those functions manipulate QGraphicsItems and whenever that is the case I get
error messages reading: "QObject::startTimer: timers cannot be started from another
thread".
Option 2: Posting an event via QMetaObject::invokeMethod()
Trying to circumvent this problem by properly posting an event for myObject, I
tried to mark MyObject::doSomeWorkWithData() with Q_INVOKABLE, but I failed at invoking the
method as I need to pass arguments with Q_ARG. I properly registered and declared my custom types
represented by struct A, etc. in the example), but I failed at the fact the
Q_ARG expanded to include a literal of the type of the argument, which in the
templated case didn't work ("T" isn't a registered or declared type).
Trying to use conventional signals and slots
This approach essentially directly failed at the fact that the QMeta system doesn't
work with templates, i.e. it seems to me that there simply can't be any templated QObjects.
What I would like help with
After spending about a week on attempting to fix this, reading up on threads (and uncovering some other issues in my code), I would really like to get this done right.
As such, I would really appreciate if :
somebody could show me a generic way of how a QObject's member function can be called via a callback function from another 3rd-party library (or anything else for that matter) from a different, non QThread-controlled, thread.
somebody could explain to me why Option 1 works if I simply don't create a GUI, i.e. do all the same work, just without a QGraphcisScene visualizing it (and the project's app being a QCoreApplication instead of a QApplication and all the graphics related work #defineed out).
Any, and I mean absolutely any, straw I could grasp on is truly appreciated.
Update
Based on the accepted answer I altered my code to deal with callbacks from other threads: I introduced a thread check at the beginning of my void doSomeWorkWithData() functions:
void doSomeWorkWithData(A a)
{
if( QThread::currentThread() != this->thread() )
{
QMetaObject::invokeMethod( this,"doSomeWorkWithData"
,Qt::QueuedConnection
,Q_ARG(A, a) );
return;
}
/* The actual work this function does would be below here... */
};
Some related thoughts:
I was contemplating to introduce a QMutexLocker before the if statement, but decided against it: the only part of the function that is potentially used in parallel (anything above the return; in the if statement) is--as far as I understand--thread safe.
Setting the connection type manually to Qt::QueuedConnection: technically, if I understand the documentation correctly, Qt should do the right thing and the default, Qt::AutoConnection, should end up becoming a Qt::QueuedConnection. But since would always be the case when that statement is reached, I decided to put explicitly in there to remind myself about why this is there.
putting the queuing code directly in the function and not hiding it in an interim function: I could have opted to put the call to invokeMethod in another interim function, say queueDoSomeWorkWithData()', which would be called by the callback in the listener and then usesinvokeMethodwith anQt::AutoConnection' on doSomeWorkWithData(). I decided against this as there seems no way for me to auto-code this interim function via templates (templates and the Meta system was part of the original problem), so "the user" of my code (i.e. the person who implements doSomeWorkWithData(XYZ xyz)) would have to hand type the interim function as well (as that is how the templated type names are correctly resolved). Including the check in the actual function seems to me to safe typing an extra function header, keeps the MyClass interface a little cleaner, and better reminds readers of doSomeWorkWithData() that there might be a threading issue lurking in the dark.
It is ok to call a public function on a subclass of QObject from another thread if you know for certain that the individual function will perform only thread-safe actions.
One nice thing about Qt is that it will handle foreign threads just as well as it handles QThreads. So, one option is to create a threadSafeDoSomeWorkWithData function for each doSomeWorkWithData that does nothing but QMetaMethod::invoke the non-threadsafe one.
public:
void threadSafeDoSomeWorkWithData(A a) {
QMetaMethod::invoke("doSomeWorkWithData", Q_ARG(A,a));
}
Q_INVOKABLE void doSomeWorkWithData(A a);
Alternatively, Sergey Tachenov suggests an interesting way of doing more or less the same thing in his answer here. He combines the two functions I suggested into one.
void Obj2::ping() {
if (QThread::currentThread() != this->thread()) {
// not sure how efficient it is
QMetaObject::invoke(this, "ping", Qt::QueuedConnection);
return;
}
// thread unsafe code goes here
}
As to why you see normal behaviour when not creating a GUI? Perhaps you're not doing anything else that is unsafe, aside from manipulating GUI objects. Or, perhaps they're the only place in which your thread-safety problems are obvious.
If an object of type QObject is moved to a thread with QObject::moveToThread, all signals that the object receives are handled inside that thread. However, if a slot is called directly (object->theSlot()) that call will still block. What would be the normal way of executing that call inside the thread and returning control to the calling thread immediately? Hacks with QTimer don't count. Setting up a single purpose connection and deleting it again might count as a solution if all else fails.
You could use QMetaObject::invokeMethod with Qt::ConnectionType set to Qt::QueuedConnection
You can use QFuture<T> QtConcurrent::run ( Function function, ... ) to launch some execution inside a separate thread and then use QFutureWatcher to get the result. You will not need to call movetoThread.
Basically something like :
QFutureWatcher<T>* watch = new QFuture(0);
connect(watch, SIGNAL(finished()), this, SLOT(handleResult()));
QFuture<T> future = QtConcurrent::run( myObj, &QMyObject::theSlot(), args...);
watch.setFuture(future);
....
//slot
private void handleResult(){
if(future->isCancelled())
return;
T mydata = watch->future()->result();
// use your data as you want
}
QtConcurrent::run will schedule the method of this object to be ran in some thread. It is non-blocking. On the other hand, QFuture::result() blocks until there is a result, if the computation is still ongoing. That's why you need the other object to notify when the computation is over using finished(). I cannot think of a better design for your problem in Qt.
I have a class 'Downloader' derived from QObject that runs in a worker thread. When the thread is started, the downloader creates a QNetworkAccessManager object on the heap, and starts to request files. I keep track of how many files have been requested and received. Once I've gotten all of the files, I delete the QNetworkAccessManager object and exit the thread. My problem is that deleting the manager object causes a crash no matter when or where I do this. I've even tried manager->deleteLater(). If I don't delete it, my code runs great, but I know there is a memory leak there. Here is a stripped down version of my code.
Creating the downloader and thread, and setting signals up so that starting the thread starts the downloads, and when the downloads are complete, the thread stops:
QThread thread;
Downloader downloader;
downloader.setFiles(files);
downloader.moveToThread(&thread);
downloader.connect(&thread, SIGNAL(started()), SLOT(downloadFiles()));
thread.connect(&downloader, SIGNAL(downloadsFinished()), SLOT(quit()));
thread.start();
Implementation for the downloader:
void Downloader::downloadFiles()
{
QNetworkAccessManager *manager = new QNetworkAccessManager();
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*)));
receivedCount = 0;
requestCount = files.count();
for (QStringList::const_iterator pos = files.begin(); pos != files.end(); ++pos)
{
QUrl url(*pos);
manager->get(QNetworkRequest(url));
}
}
void Downloader::finished(QNetworkReply *reply)
{
// *** Get the file data and process it *** //
++receivedCount;
reply->deleteLater();
if (receivedCount == requestCount)
{
// manager->deleteLater();
emit downloadsFinished();
}
}
The commented out line will crash the app. Even deleting the manager in Downloader's destructor, or setting the downloader as the manager's parent will crash the app.
I first tried creating the manager as a regular member variable on the stack, but doing so causes errors of it's own since the manager would be created in the GUI thread and later try to create children on a different thread.
And before anybody says "QNetworkAccessManager is asynchronous. Why use it in a worker thread?" I have my reasons. It shouldn't be THAT unheard of to do something like this.
The only obvious problem is below but I am not sure if you have posted your entire code or not
void Downloader::downloadFiles()
{
QNetworkAccessManager *manager = new QNetworkAccessManager();
You are creating a local QNetworkAccessManager *manager in your method but not keeping a reference to it and then trying to access it within finished() method.
You should assign new QNetworkAccessManager(); a member variable !
Can somebody please explain why the event "OnNewMail" is not raised when using an STA thread in the code below? The program attempts to use the Redemption library to intercept incoming outlook mails.
class Program
{
[STAThread()] // When this line is deleted the application works
static void Main(string[] args)
{
RDOSession session = GetSession();
session.OnNewMail += Session_OnNewMail;
Console.ReadLine();
}
static void Session_OnNewMail(string EntryID)
{
Console.WriteLine("New mail received");
}
private static RDOSession GetSession()
{
var session = new RDOSession();
var application = new ApplicationClass();
session.MAPIOBJECT = application.Session.MAPIOBJECT;
return session;
}
}
COM running on an STAThread uses a message pump to raise events and call methods. When in a console application there isn't a window to pump messages for you so you need to run the pump yourself. (Several of the .NET synchronisation methods will do this for you - have a look at WaitOne etc...)
If the object is happy within a default MTA thread - you may be better off using that if you need to do this from a console application.
Instead of ReadLine - you can poll for a key and pump messages using this:
while (Console.Read() == 0)
{
Thread.CurrentThread.Join(100);
}
...but this is a hack.
Mixing COM, console apps and [STAThread] is a bit fishy and can result in other problems:
http://support.microsoft.com/default.aspx/kb/828988
When the tread is STA thread and you wait for input the library can't do anything at the same time and has no chance to fire the event when an email arrives.
The problem almost certainly has to do with message pumping.
Unless we know what type of COM object RDOSession is (STA, MTA, etc ...) we can only speculate as to what is actually going on.
My guess is that RDOSession is an MTA COM object and that somehow the event code has bound the event to an STA proxy or object. This means that part of the raising of the OnNewMail event must marshal the raise onto the STA thread. This involves window message passing. You are doing a simple ReadLine call which is a blocking call and will not process messages. Hence you won't ever get the event.