I am replacing the OpenGL code of my C++ app with code that uses OpenSceneGraph.
The app is based on Qt and using Qt Threads.
The main thread is calling the viewer->frame() while other threads are loading data.
Those threads directly works whith my scene graph, adding node with addChild().
But sometimes this group->addChild call make my app crash. I Can see, in the stacktrace, the group's vector containing the children is resizing.
I guess that I'm not supposed to add childrens in one thread while another may be drawing it. Am I right ?
What is the best way to do it ? Using a update callback ? Locking the main thread ?
Related
I currently have a C++ class inheriting from QQuickPaintedItem. I use it to paint layouted, paginated richtext from a QTextDocument via QTextDocument::drawContents (or by directly calling its QTextDocumenLayout's draw method).
However, as stated in QQuickPaintedItems documentation, there are threading issues to be aware of:
Warning: Extreme caution must be used when creating QObjects, emitting signals, starting timers and similar inside this function as these will have affinity to the rendering thread.
Specifically, in this case, QTextDocumentLayoutPrivate has timers which get started/stopped when QTextDocumenLayout::draw is called. Unfortunately, the QTextDocument and thus the timers lives in the qml main thread, while paint is called in the render thread, leading to messages like
QBasicTimer::start: Timers cannot be started from another thread
While this doesn't affect the functionality of my application (so far), this is probably not a good thing™.
Therefore, my question is whether there is a better way to show the paginated text in QML (not necessarily involving QQuickPaintedItem).
For now I'm still using the QQuickPaintedItem and when paint is called I do the following:
First check whether the QTextDocument has its affinity set to its current thread. If yes, I'll proceed as normal.
Otherwise QMetaObject::invokeMethod is used to call a method which moves the document to the rendering thread, and calls update to trigger a repaint, which now works as the thread affinity is correct. At the end of paint, the QTextDocument's thread affinity is set back to the original thread.
This works as far as I can tell (as in, no more warnings), but feels conceptually rather wrong.
My program work with 2 threads (boost::thread) and, of course, 1 mainloop.
The problem is that I currently update 2 widgets at the end of each threads, and thoses updates sometime provoke segmentations faults.
I use the function "gtk_widget_queue_draw" to update widgets into my threads.
I saw somewhere on the web that we must update all of our widgets into the main loop and never into threads, so my question is simple, how do I do that ?
With signals maybe ?
I already tried with the fundtion "g_idle_add" but it don't work either.
It seems that I can also use gtk_thread_enter and gtk_thread_leave but thoses two functions are deprecated.
Thanks
Edit: I almost forgot; if I want to update manually my widgets, it's because they don't updates automatically (and one of thoses widgets is a chart drawn with cairo)
"g_idle_add" seem to be the good way to do that, but it ends up with segmentation fault too.
Here is the way I implemented this:
In my thread:
g_idle_add ((GSourceFunc)update_label_monitor_cpu, &string_cpu);
And the function itself:
void update_label_monitor_cpu(std::string *str)
{
std::string tmp = *str;
gtk_label_set_label(GTK_LABEL(label_monitor_cpu), (gchar*)tmp.c_str());
}
g_idle_add() is the correct way to do this. You get a segmentation fault because your strings go out of scope, and are destroyed, before the idle callback ever runs. You'll need to manually manage the memory for the strings in your idle callback; for instance, using g_strdup() and g_free().
i m using cocos2d-x V3.4 and i still cannot find a good example on how to use multi threading. i m using pthread as worker thread to do some background processing. from within the pthread,i trigger some custom events (Director::getInstance()->getEventDispatcher()->dispatchEvent(&evt);) to update the UI.things are working fine as long as the triggered events do not add any graphic to the UI (addChild). moving sprites around doesnt look to have any issue. but once the pthread fires an event (EventCustom) that needs to add a ui node (DrawNode in my case), i get a black screen. from what i could find on the web, the pthread is not supposed to fire those events. he just need to fill up a queue of events and schedule pulling those events from the UIThread to render. What i did was having an std::vector as member of a singleton class GameManager. my pthread pushes to that list. and i scheduled a pulling from that list. but my app keep crashing. So i m pretty sure that what i m doing is not the right way.
UI related stuff must be performed on cocos thread otherwise it may lead to undefined behaviour as per my experience.
You can try following steps:
Create a function that will perform required UI related stuff on a particular event
Call the method from your pthread to be performed on cocos thread as follows:
auto scheduler = Director::getInstance()->getScheduler();
scheduler-> performFunctionInCocosThread(CC_CALLBACK_0(YourClass::updateUI, this));
Here updateUI function which is defined in YourClass will be responsible to perform UI related operations.
I just have a simple question, with a Windows Runtime Component (as in a library) that I am making how do I get the window object for the app? CoreWindow::GetForCurrentThread() throws an exception as it seems that the library runs in a different thread then the app. Any one know how to get the app window?
EDIT: GetForCurrentThread is not the problem, it seems that that it only works on the UI thread not a background thread, I would like a way to get at it from a background thread. Is it possible?
I think Window.Current is what you are looking for.
I'm kind of stuck on something; regarding spawning multiple forms in OOP.
The message loop most of the time is (wxWidget's case) window->show();
bool MyApp::OnInit()
{
MainWindow *oWindow = new MainWindow(wxT("My Window"));
oWindow->Show(true);
return true;
}
Others have oWindow->run(), but anyway my question is:
I've created a second thread with the exact same structure of the function above and called the message loop method. The problem is that the window appears and dissapears suddenly which doesn't make sense to me. If however I call:
MainWindow *oWindow = new MainWindow(wxT("My Window"));
oWindow->Show(true);
MainWindow *oWindow2 = new MainWindow(wxT("My Window"));
oWindow2->Show(true);
It will work, but I don't want that as I will need to keep track of the windows I create and have them on separate threads. What can I do?
You cannot run wxWidgets windows in anything other than the main thread.
"GUI calls, such as those to a wxWindow or wxBitmap are explicitly not safe at all in secondary threads and could end your application prematurely. This is due to several reasons, including the underlying native API and the fact that wxThread does not run a GUI event loop similar to other APIs as MFC."
http://docs.wxwidgets.org/2.8/wx_wxthread.html
BTW, I cannot imagine any situation where what you want to do is a good idea. There is never any need to tun windows in more than one thread.
A windows program is event-driven. You can as have as many top level windows as you want, but there should be just one event queue so that the events on two windows do not end up in contention for the same resource. This is why wxWidgets prevents you trying to create two threads both handling windows events.