Threads and QGraphicsScene
-
I want to use threading to make my Qt app run smoother. I am using a thread instantiated using QtConcurrent::run that adds QGraphicsItems into a QGraphicsScene.
The code to launch the thread in the main app looks like this:
connect( &m_ThreadFuture , SIGNAL(finished()), this , SLOT(GraphicsDrawn())); m_ThreadFuture.setFuture( QtConcurrent::run( DrawGraphics , &m_Scene ));
Where the DrawGraphics function takes a pointer to the QGraphicsScene object.
To view, when the thread is finished, I assign the QGraphicsScene to a QGraphicsView using setScene; thats what the GraphicsDrawn SLOT is doing. It does work so I see the graphics I expect but the app is unstable and I see warnings in the Application Output window:
QObject::startTimer: Timers cannot be started from another thread
I am not using any timers in my App and all the QGraphicsItems are QGraphicsLineItems. If I don't use a thread and I call all the functionality within the main thread all is stable and no warnings appear in the Application Output window. Any thoughts?
Thanks In Advance
John T.
-
To my best knowledge, the QGraphicsView framework is not designed for multithreading.
That said, there might well be alternatives to make your app run smoother. Have you actually identified item creation and initialization as one of the reasons for your problems? If so, what number of items are we talking about?
Some wild ideas (without knowing the context):
- Reuse items instead of deleting and new'ing them
- Combine combinations of items you use often into one larger item (e.g. draw a polyline instead of inserting hundreds of QGraphicsLineItems)
- While talking about lines: Don't draw with cosmetic pens of width > 1
- Create a "initialization todo list". Have a timer run in the main thread. Every time the timer event is triggered, perform the initialization of x items, then yield control to keep the app responsive
-
Thanks for the reply. Yes I am almost certain you are correct. I have been looking at the stack traces when the app dies and in all cases the crash has something to do with an event and notification. Here is a stack trace:
0 ntdll!RtlpNtMakeTemporaryKey C:\Windows\SYSTEM32\ntdll.dll 0x770a56bd 1 ntdll!EtwSetMark C:\Windows\SYSTEM32\ntdll.dll 0x77071ab3 2 ntdll!RtlpNtMakeTemporaryKey C:\Windows\SYSTEM32\ntdll.dll 0x770a6717 3 ntdll!EtwSetMark C:\Windows\SYSTEM32\ntdll.dll 0x7706a13e 4 wcsnicmp C:\Windows\SYSTEM32\ntdll.dll 0x770365a6 5 msvcrt!free C:\Windows\system32\msvcrt.dll 0x758198cd 6 ?? 0x183f0000 7 QArrayData::deallocate 122 0x6b79a890 8 QTypedArrayData<QGraphicsItem*>::deallocate 222 0xd50b3f3 9 QVector<QGraphicsItem*>::freeData 484 0xd59b341 10 QVector<QGraphicsItem*>::~QVector 68 0xd59b4d2 11 QVector<QGraphicsItem*>::clear 385 0xd59ada9 12 QGraphicsScenePrivate::_q_polishItems 453 0xd47c4fa 13 QGraphicsScene::qt_static_metacall 180 0xd491d93 14 QMetaCallEvent::placeMetaCall 485 0x6b9536c0 15 QObject::event 1245 0x6b954485 16 QGraphicsScene::event 3471 0xd4856f3 17 QApplicationPrivate::notify_helper 3720 0xd1af4dd 18 QApplication::notify 3164 0xd1aceb0 19 QCoreApplication::notifyInternal 935 0x6b92ee90 20 QCoreApplication::sendEvent 228 0x6b9d4e9f 21 QCoreApplicationPrivate::sendPostedEvents 1552 0x6b930028 22 QCoreApplication::sendPostedEvents 1410 0x6b92fb0e 23 QWindowsGuiEventDispatcher::sendPostedEvents 81 0x2e5de899 24 qt_internal_proc(HWND__*, unsigned int, unsigned int, long)*16 412 0x6b97d638 25 gapfnScSendMessage C:\Windows\system32\user32.dll 0x76bdc4e7
Looking at the man pages it appears that QGraphicsScene does emit a changed() signal whenever items are added so, if this is not in the main thread, I guess it could cause a problem.
Thanks also for the advice:
Create a "initialization todo list". Have a timer run in the main thread. Every time the timer event is triggered,
perform the initialization of x items, then yield control to keep the app responsive.Funnily enough this is the way the original X/Motif application that I am porting actually works. I was just trying to be clever using threads; you win some you lose some.
Thanks again for the response and the interest.
John T.