On GLFW FAQ, item 2.9 it is stated:
[...] It is strongly recommended that all OpenGL and GLFW calls
(except for thread management and synchronization calls) are made from
the main thread, which should not be a big problem since only a single
window is supported. This method is also compatible with the future
direction of GLFW.
The emphasis is mine.
So, what is the difference between the main thread and other threads?
The question refers to an old GLFW API and FAQ, please see the updated GLFW FAQ, and GLFW thread safety documentation.
Some constraints remain, and many GLFW calls must be made from the main thread. The difference between the main thread and other threads depends on platform specific behaviour for window creation, events etc which GLFW handles. For more detail please see this post on the official GLFW forum.
Once an OpenGL window has been created, the context can be made current on another thread and OpenGL calls can be made from that thread.
The statement
"Is … thread safe? No. However, neither is OpenGL."
is wrong. OpenGL is of course thread safe.
Here's the deal: For each thread either one or no OpenGL context can be bound to a drawable (made current). OpenGL calls operate on the context that is active in the thread the calls are made from. It is perfectly possible to transfer a OpenGL context between threads. For this the context to be transfered first must be unbound, then it can be rebound in another thread.
Each OpenGL context manages its own set of state variable and objects (textures, buffers). However context can be "entangled", i.e. share their object space. State is still individual though.
A single drawable (window, PBuffer) can have multiple contexts from different threads being bound to. If contexts from different threads draw to the same drawable a race condition occours and the results are undefined. However in the case of depth tested drawing the outcome should be reasonable. However simultanous drawing to a single drawable will strongly impair performance, so it better is avoided.
The main use for multiple OpenGL contexts in multiple threads is to share their objects so that one thread can load and update data for the other context. It makes sense to bind the helper contexts to off-screen or hidden drawables to prevent race conditions to happen.
There's no technical difference between the threads. From a programming point of view each thread will have a slightly different semantic, which is imposed by the programm running, not by the system architecture. In the case of most OpenGL applications the conventional semantics are, that the main thread will create the window, draw all elements visible to the user (including OpenGL operations) and collect user input. The threads launched from the main thread are worker threads without direct user interaction. However this task distribution is purely by choice and because it turned out to work well. But it's perfectly possible, and sometimes advisable, to use a different scheme. And like already said, there is no technical difference about the threads within a program. All threads are equal rights citizens within a process.
The documentation is maybe worded in a slightly misleading way. A better wording would be:
It is strongly recommended that all OpenGL and GLFW calls (except for thread management and synchronization calls) are made from a single thread, preferrably the same one that called glfwInit and glfwOpenWindow, which should not be a big problem since only a single window is supported. This method is also compatible with the future direction of GLFW.
The reason for that is that OpenGL has the concept of a "current thread" for its contexts, which is the one thread that may legitimate modify or use that context at a given time. A context initially belongs to the thread that created it. You can make it "current" in some other thread by calling wglMakeCurrent or glxMakeCurrent, which unlike GLFW is not portable (but GLFW might have a wrapper for that, I'm not sure).
It is of course very well possible to have several independent contexts, and it is possible to access the same context from several threads by making the same context current in each thread prior to using it. And lastly, it is possible to have several contexts in several threads that share state.
However, none of these options is the regular case, as it either involves non-neglegible synchronization overhead or is not suitable for the common usage of OpenGL. Any other thing than "one thread, one context" usually, with very few exceptions, doesn't offer any advantage, but comes with needless complexity.
The regular case is therefore to have exactly one context that is used by exactly one thread, and optionally some worker threeads that help with shuffling data into mapped buffers.
As for "main thread" versus "any thread", there is no difference. The main thread is just incidentially the one that initializes GLFW (and thus OpenGL), most of the time.
Related
Details about the issue leading to the question
We're facing a SIGSEGV error under extremely rare circumstances when using the lmdb database library that are not easily reproducible. The best we got out of it is a stack-trace that looks like this through the core dump:
#0 in mdb_env_reader_dest (ptr=...) at .../mdb.c: 4935
#1 in __nptl_deallocate_tsd () at pthread_create.c:301
...
The line the stack-trace is pointing to is this (it's not the same because we attempted some changes to fix this).
Having tracked the issue for a while, the only explanation I have is that, when closing the lmdb environment from a thread other than the main thread, there's some kind of race between this line and this line, where the latter deletes the key, calls the custom destructor mdb_env_reader_dest, which causes SIGSEGV according to the documentation of lmdb, when attempting to use resources after freeing them.
The question
The documentation of pthread_key_create and pthread_key_delete are ambiguous to me, personally, in the sense whether they're talking about the calls to pthread_key_create and pthread_key_delete or the data underneath the pointers. This is what the docs say:
The associated destructor functions used to free thread-specific data at thread exit time are only guaranteed to work correctly when called in the thread that allocated the thread-specific data.
So the question is, can we call mdb_env_open and mdb_env_close from two different threads, leading to pthread_key_create and pthread_key_delete from different threads, and expect correct behavior?
I couldn't find such a requirement in the lmdb documentation. The closest I could find is this, which doesn't seem to reference the mdb_env_open function.
Are we allowed to call pthread_key_create and pthread_key_delete from different threads?
Yes.
However, a key must be created via pthread_key_create before it can be used by any thread, and that is not, itself, inherently thread safe. The key creation is often synchronized by performing it before starting any (other) threads that will use the key, but there are other alternatives.
Similarly, a key must not be deleted before all threads are finished with it, and the deletion is not, itself, inherently thread safe. TSD keys often are not deleted at all, and when they are deleted, that is often synchronized by first joining all (other) threads that may use the key. But again, there are other alternatives.
The documentation of pthread_key_create and pthread_key_delete are
ambiguous to me, personally, in the sense whether they're talking
about the calls to pthread_key_create and pthread_key_delete or the
data underneath the pointers. This is what the docs say:
The associated destructor functions used to free thread-specific data
at thread exit time are only guaranteed to work correctly when called
in the thread that allocated the thread-specific data.
The destructor functions those docs are talking about are the ones passed as the second argument to pthread_key_create().
And note well that that text is drawn from the Rationale section of the docs, not the Description section. It is talking about why the TSD destructor functions are not called by pthread_key_delete(), not trying to explain what the function does. That particular point is that TSD destructor functions must run in each thread carrying non-NULL TSD, as opposed to in the thread that calls pthread_key_delete().
So the question is, can we call mdb_env_open and mdb_env_close from
two different threads, leading to pthread_key_create and
pthread_key_delete from different threads, and expect correct
behavior?
The library's use of thread-specific data does not imply otherwise. However, you seem to be suggesting that there is a race between two different lines in the same function, mdb_env_close0, which can be the case only if that function is called in parallel by two different threads. The MDB docs say of mdb_env_close() that "Only a single thread may call this function." I would guess that they mean that to be scoped to a particular MDB environment. In any case, if you really have the race you think you have, then it seems to me that your program must be calling mdb_env_close() from multiple threads, contrary to specification.
So, as far as I know or can tell, the thread that calls mdb_env_close() does not need to be the same one that called mdb_env_open() (or mdb_env_create()), but it does need to be the only one that calls it.
There are lots of functions that are supposed to be called from the main thread. In my limited experience, these are mostly UI functions.
Examples:
-[UIApplication delegate] must be called from main thread only)
java.lang.IllegalStateException: Not on the main thread
Drawing to window from child thread
Suppose I have a fiber library that creates "threads" with set/get context. Is it safe to call main thread only functions from any fiber started from the main OS thread?
I think it is fine since the OS doesn't know about my fibers, but I'm not sure. I would test this, but the results would not be definitively since it might work but be relying on undefined behavior.
Edit: marking this question C since set/get context are C functions, although as mentioned in the comments I think it may apply to programs written in other languages as well.
Yes, you can call any function in your program from any context. Note that using getcontext and setcontext are not making real "threads", and you're not getting any parallel processing with this - you're only getting scheduling. That's why it will work, no matter if it's a UI function or not. It's basically just a goto that works cross-function. To quote the manpage directly:
If the context was obtained by a call of getcontext(), program
execution continues as if this call just returned.
That means if I write
... code ...
getcontext(&cxt);
... code ...
setcontext(&cxt);
Then when I reach setcontext, the state that I go to is identical to when the function getcontext just returned. There is no perceivable difference (Of course, you may have changed memory values in the mean time, but that's beside the point). The manpage has a similar guarantee with makecontext, but with the note that it'll redirect you after the given function finishes execution.
The examples you give are in higher level programming langauges, which have a lot more complexity, and thus are not as simple as setcontext/getcontext in C. The Java Error you posted seems to actually be a distinct OS thread, and same with the third example. The first example looks like it might be a fake thread but of course there are hidden complexities which might prevent UI calls from working (Since they interact with external APIs).
That's why threading in JS is so easy: because the threads aren't real. What you lose in parallel performance you gain in being able to call anything anywhere from your dispatched functions and ajax calls.
If you know your fiber library is really only using getcontext and setcontext, then you'll be fine. The library might do something else though, so it would be good to verify with the library writers in such a situation.
I am implementing an application which executes two programs in lockstep. Each system call is a synchronization point. An application might have more than one thread, thus I need to identify unequivocally each of them in order to synchronize the execution of a thread from the first application with the execution of the same thread in the second application.
Is there a way to identify if two remote threads are executing the same code or function?
Every suggestion is welcomed!! :D
Well it's hard to say not knowing how you plan to do this synchronization. Are the two program communicating to each other and/or a third monitoring pgm?
In any case there are at least 3 possibilities:
Use an associative container like a map in the two programs (or the 3rd) that matches up
the pthread thread ids from the two programs (e.g. pthread_self() to get the tids)
the linux thread ids (e.g. gettid())
Or you can possibly make use of pthread_setname_np() and pthread_getname_np(). You can use these to give each thread in both programs the same name and maybe that becomes useful in some messaging scenario. You might also make use of the __FILE__, __LINE__ and __FUNCTION__ (__func__ in c99) macros in conjuction with the thread name if you are messaging.
That's my (black box) suggestions!
I want to write a high performance synchronized generator in C. I want to be able to feed events to it and have multiple threads be able to poll/read asynchronously, such that threads never receive duplicates.
I don't really know that much about how synchronization is typically done. Can someone give me a high level explanation of one or more techniques that I might be able to use?
Thanks!
You need a thread implementation; C does not have any built-in support for multiprocessing concepts. Threads are thus often implemented as libraries. Such a library will typically provide you with ways to synchronize the execution of multiple threads, ways to protect data, and so on.
The main concept in thread safety is the Mutex (though there is different kind of locks).
It is used to protect your memory from multiple accesses and race conditions.
A good example of its use would be when using a Linked List. You can't allow two different threads to modify it in the same time. In your example, you could possibly use a linked-list to create a queue, and each thread would consume some data from it.
Obviously there are other synchronization mechanisms, but this one is (by far ?) the most important.
You could have a look at this page (and referenced pages at the bottom) for more implementation details.
Thread-safe will be the problem when there are shared variables between threads. If you don't have any shared variables, it's not a problem. Every event can be readonly and disptaching to listeners randomly.
Thread safety is achieved by using whatever synchronisation primitives the multithreading implementation provides.
Your start point would probably be a linked list of events, a lock that protects it, and every thread takes the lock, consumes one event by adjusting the pointer to the first event and then releases the lock; appending events also locks the entire list. When the list is empty, the workers exit.
From there, various optimisations are possible:
Caching the pointer to the last event, so appending an event to the list becomes cheaper.
Adding a notification mechanism so worker threads can sleep while the list is empty. Typically, this is achieved with something called a condition variable.
Using multiple lists, so if the first list is locked, the worker can retrieve an event from another list without having to wait for the thread that has currently locked the list.
I’m buried in multithreading / parallelism documents, trying to figure out how to implement a threading implementation in a programming language I’ve been designing.
I’m trying to map a mental model to the pthreads.h library, but I’m having trouble with one thing: I need my interpreter instances to continue to exist after they complete interpretation of a routine (the language’s closure/function data type), because I want to later assign other routines to them for interpretation, thus saving me the thread and interpreter setup/teardown time.
This would be fine, except that pthread_join(3) requires that I call pthread_exit(3) to ‘unblock’ the original thread. How can I block the original thread (when it needs the result of executing the routine), and then unblock it when interpretation of the child routine is complete?
Use a pthread_cond_t; wait on it on one thread and signal or broadcast it in the other.
Sounds like you actually want an implementation of the Thread Pool Pattern. It makes for a fairly simple conceptual model, without repeated thread creation & tear down costs. Some OS's directly support it, on others it should be reasonably simple to implement using a queue and a semaphore.