Must Webkit always be used on the main thread? - multithreading

I'm trying to render webpages in the background and I ran into the following trouble
2012-05-11 12:39:02.086 [77207:1c03] An uncaught exception was raised
2012-05-11 12:39:02.087 [77207:1c03] objc_object* -[WebView initWithFrame:frameName:groupName:](WebView*, objc_selector*, CGRect, NSString*, NSString*) was called from a secondary thread
I understand that webkit classes are not thread-safe, but do they also have to be always used from the main thread? Alternatively, can I create a dummy web view just to initialize webkit and then later use webkit classes from background threads?

WebView is a subclass of NSView. From the Threading Programming Guide:
The NSView class is generally thread-safe, with a few exceptions. You
should create, destroy, resize, move, and perform other operations on
NSView objects only from the main thread of an application. Drawing
from secondary threads is thread-safe as long as you bracket drawing
calls with calls to lockFocusIfCanDraw and unlockFocus.
(Emphasis added.)
I'm less clear on how the AppKit WebView works, but my understanding is that in UIKit there is really only one UIWebView that just gets reused all over for performance reasons, something akin to the field editor in AppKit. If my understanding is correct, and WebView behaves similarly, I could see you having even bigger problems with background threading.

Related

Thread safety in Unity

In Unity, the thread cannot operate the object provided by UnityEngine like transform.position etc, which caused an exception that get_transform can only be called from the main thread.
However, these methods can be used in some async function like BeginReceive, so is there anyone can tell me why? The async function is not thread or sth else?
I try the code below:
void Start(){
AsyncCallback callback = new AsyncCallback (demo);
callback.BeginInvoke (null, null, null);
}
void demo(IAsyncResult result){
Debug.Log(Thread.CurrentThread.ManagedThreadId);
Debug.Log(gb.transform.position.ToString());
}
It does throw an exception when I run the code on Unity Editor. However, when I run this code on an Android phone directly, it didn't throw any exception and the code was performed correctly.
The log in applogcat shows that:
Line 13497: 02-20 14:37:49.973 31027 31697 I Unity : 3
Line 13501: 02-20 14:37:49.975 31027 31697 I Unity : (0.0, 0.0, 0.0)
So it seems that the function runs on another thread instead of main thread, so could anyone tell me why transform works on this situation?
Unity doesn't allow calling most API functions from threads other than the main thread, period. All of the event/message processing is actually done on the main thread.
The coroutine system based on IEnumerator is a bit of a hack and doesn't actually allow for multi-threading (keep in mind that even the .NET 4.5 async/await feature doesn't necessarily imply multithreaded execution either).
If calling the UnityEngine API works, you're on the main thread.
UI APIs aren't allowed to be called from a different thread than the UI one.
This simplifies how Unity works behind the scenes and actually makes it faster.
Some async methods are dispatched using an event loop and not a different thread. Just because a method is async it doesn't mean it gets to run on a different thread.
The most obvious example of this in Unity are Coroutines. They do run async, but on the main thread. This is possible because Unity adds all of to a list and executes them every frame.
You can call the Unity API from other threads, but NOT if you're running the game from within the Unity Editor. Release builds do not check which thread the call to the Unity API originated from. I assume they don't bother to avoid the performance hit.
I haven't tested this much myself though. The Unity documentation is quite clear that the API is not thread-safe. Therefore, definitely don't make any property assignments or calls that change the game state from other threads. Merely reading values might be OK, but it depends on the unknown internal caching behavior of UnityEngine, ie. hashtables/dictionaries would be bad for multi-threading.

OpenGL context and thread error with QGLWidget

I'm working on the migration, from Qt 4.8 to Qt 5.5, of a quite big app using a QGLWidget.
My error is "Cannot make QOpenGLContext current in a different thread".
What I understood about this error is that, as the error say, the openGL context can only be binded to one thread, and only this thread can use the context.
Old code was like :
myQGLWidget->makeCurrent();
.. some openGL
myQGLWidget->doneCurrent();
This was working in Qt 4.8, with some thread lock to avoid concurrent call to that "makeCurrent".
After reading all what I could on the subject, my last try was :
myQGLWidget->context()->moveToThread(QThread::currentThread());
myQGLWidget->context()->makeCurrent();
... openGL again
myQGLWidget->context()->doneCurrent();
I still get the same error...
I'm a bit confused about how it's supposed to work, can someone help me ?
Regards,
The error is about a combination of two things:
QGLContext in Qt 5 is a small wrapper around QOpenGLContext;
QOpenGLContext is-a QObject (hence, it has QObject semantics when it comes to threading), and for some reason it also employs a fatal check that forbids you to call makeCurrent on it from a thread different than the thread it has affinity with ("affinity" here being the QObject concept).
If you're in control of both threads the best thing to do might be simply creating a new QGLContext, sharing with your QGLWidget's context; and then move and use this new context into the thread. You still need the locking you already have -- you can't make two contexts current on the same surface.
More in general, this is recognized as a limitation of QOpenGLContext. I've already prepared a patch for Qt 5.8 to try to get rid of it, you can find it here.

MFC: how to draw opengl from a different thread?

I am trying to do some opengl 1.0 animation in a CWnd window with 60 fps. I create a sub class of CWnd:
class COpenGLControl : public CWnd
{
...
}
I found if I use the build-in timer "setTimer()" and set it to fire on every 1000/60 ms, all the opengl commands were able to render correctly. However, If I implement my own timer using a separate thread, nothing is drawn. All I got was a black screen.
Is there a way to issue opengl commands from a different thread?
Even if you are not intending to issue GL calls from multiple threads, you have to take OpenGL's rules for threading into account: An OpenGL context can only be used by at most one thread at a time. (And, per thread, there can be at most one active GL context at any time). That does not mean that you cannot use the same context in multiple threads, or create it in one and use it in another, you just have to explicitely "hand over" the context from one thread to another.
I don't know if you use some further librariy for GL context handling, so I'm assuming you are using the native API of your OS - in this case wgl. The relevant function is wglMakeCurrent(). So, to hand over a context which is "current" in thread A to thread B, thread A must first call wglMakeCurrent(NULL,NULL) before thread B can get the context via wglMakeCurrent(someDC, myGLCtx). You can of course switch around a GL context as many times you like, but that will introduce a huge synchronization overhead and should be avoided.
From your comments:
Would work If I create the context also in the timer thread?
Yes, it would.
Just a side note: Creating is not the issue here at all, since creating a GL context does not automatically make it "current" to a thread - so you can just create it in thread A and afterwards make it current directly to thread B.

how to use GetDlgItemText inside and outside of worker thread

I am having a problem with using GetDlgGetItemText inside a worker thread. it is working perfectly fine outside with
TCHAR txtbuff[50];
GetDlgItemText(IDC_SLIDER1, txtbuff, 50);
SOmething = ::SendMessage(something,WM_SETTEXT,0,(LPARAM)txtbuff)
but when i try to use the same in a worker thread I get told that it doesn't take 3 arguments, because it needs it's HWND handle (from what I have gathered), which I thought was gained using winspy++ or similar, but those handles change all the time. I thought (quite wrongly because I am new to this) that I could simply use the same code inside my worker thread. how come the above code works fine outside of the worker thread? I have looked around everywhere, am I missing something blatantly obvious/simple?
The GetDlgItemText version that needs only 3 arguments is a CWnd member function. MFC translates it into the 4-argument API version using the m_hWnd member of the CWnd. So you cannot use the 3 argument version outside of a CWnd object.
Another problem is that both versions of GetDlgItemText are defined to work only for accessing child windows. So you cannot use them unless calling in the context of the parent window of the IDC_SLIDER1 control.
And another problem is that MFC does not support accessing a window/control from a thread that did not create the window. There are some limited cases where this works but it is poor practice. Even when it works it causes unobvious interactions between the threads, possibly leading to a deadlock.
Put all of your interactions with the GUI into the main thread. And put all your interactions with child windows (i.e. controls) in the parent window class.

QPointer in multi-threaded programs

According to http://doc.qt.io/qt-5/qpointer.html, QPointer is very useful. But I found it could be inefficient in the following context:
If I want to show label for three times or do something else, I have to use
if(label) label->show1();
if(label) label->show2();
if(label) label->show3();
instead of
if(label) { label->show1();label->show2();label->show3(); }
just because label might be destroyed in another thread after label->show1(); or label->show2();.
Is there a beautiful way other than three ifs to get the same functionality?
Another question is, when label is destroyed after if(label), is if(label) label->show1(); still wrong?
I don't have experience in multi-threaded programs. Any help is appreciated. ;)
I think the only safe way to do it is to make sure you only access your QWidgets from within the main/GUI thread (that is, the thread that is running Qt's event loop, inside QApplication::exec()).
If you have code that is running within a different thread, and that code wants the QLabels to be shown/hidden/whatever, then that code needs to create a QEvent object (or a subclass thereof) and call qApp->postEvent() to send that object to the main thread. Then when the Qt event loop picks up and handles that QEvent in the main thread, that is the point at which your code can safely do things to the QLabels.
Alternatively (and perhaps more simply), your thread's code could emit a cross-thread signal (as described here) and let Qt handle the event-posting internally. That might be better for your purpose.
Neither of your approaches is thread-safe. It's possible that your first thread will execute the if statement, then the other thread will delete your label, and then you will be inside of your if statement and crash.
Qt provides a number of thread synchronization constructs, you'll probably want to start with QMutex and learn more about thread-safety before you continue working on this program.
Using a mutex would make your function would look something like this:
mutex.lock();
label1->show();
label2->show();
label3->show();
mutex.unlock()
As long as your other thread is using locking that same mutex object then it will prevented from deleting your labels while you're showing them.

Resources