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.
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.
I want to improve the speed of a certain C application and for that I will be using threads. What concerns me is if I can, within a function being executed in a different thread, call another function of that is not being executed in the same thread: Example:
void checks_if_program_can_do_something()
{
}
void does_something()
{
checks_if_program_can_do_something();
}
int main()
{
does_something(); //another thread is used to execute this function
return 1;
}
In this case, the function does_something() calls the function checks_if_program_can_do_something(), but does_something() is being executed in another thread. I hope I made myself clear. Can I also call the function checks_if_program_can_do_something() in other functions using multiple threads?
Yes, but you should take care that the function does not alter state in such a way that other threads would be impacted negatively.
The terms related to this kind of protection are reentrant, which means the program can safely be paused and continued, and thread-safe which means that two non-pausing calls can be made at the same time.
These features you add to a function require programming approaches that might differ from most people's standard approaches; but, they handle two important scenarios that must be accounted for when writing threaded code:
The CPU pauses part of your program (it needs to wait on I/O) or needs the core for a different part of your program.
The CPU decides to run two threads of your program at the same time on different cores.
Gide lines for safe programming approaches are plentiful, but I've provided one here for you to get started. Keep in mind that if you use someone else's code in a threaded situation, you also need to verify that their code is written to be reentrant / thread safe.
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.
I've got some system level code that fires timers every once in a while, and has a signal handler that manages these signals when they arrive. This works fine and seems completely reasonable. There are also two separate threads running alongside the main program, but they do not share any variables, but use glib's async queues to pass messages in one direction only.
The same code uses glib's GHashTable to store, well, key/value pairs. When the signal code is commented out of the system, the hash table appears to operate fine. When it is enabled, however, there is a strange race condition where the call to g_hash_table_lookup actually returns NULL (meaning that there is no entry with the key used to look it up), when indeed the entry is actually there (yes I made sure by printing the whole list of key/value pairs with g_hash_table_foreach). Why would this occur most of the time? Is GLib's hash table implementation buggy? Sometimes the lookup call is successful.
It's a very particular situation, and I can clarify further if it didn't make sense, but I'm hoping I am doing something wrong so that this can actually be fixed.
More info: The code segments that are not within the signal handler scope but access the g_hash_table variable are surrounded by signal blocking calls so that the signal handler does not access these variables when the process was originally accessing them too.
Generally, signal handlers can only set flags and make system calls
As it happens, there are severe restrictions in ISO C regarding what signal handlers can do, and most library entry points and most API's are not even remotely 100% multi-thread-safe and approximately 0.0% of them are signal-handler-safe. That is, there is an absolute prohibition against calling almost anything from a signal handler.
In particular, for GHashTable, g_hash_table_ref() and g_hash_table_unref() are the only API elements that are even thread-safe, and none of them are signal-handler safe. Actually, ISO-C only allows signal handlers to modify objects declared with volatile sig_atomic_t and only a couple of library routines may be called.
Some of us consider threaded systems to be intrinsically dangerous, practically radioactive sources of subtle bugs. A good place to start worrying is The Problem with Threads. (And note that signal handlers themselves are much worse. No one thinks an API is safe there...)
When trying to implement an asynchronous API calls / Non-blocking calls, I know a little in a All Plain-C application I have, I read a about APM (Asynchronous Programming Model) by 'Delegates'. Basically what I want to do is call one API f1() to do a functionality(which takes long time 8-10 seconds), So I call that API f1(), forget about it, and continue doing some other work, e.g. I/O for to fetch data for next call of the f1() or some functionality not dependent on result of f1().
If any one has used that APM model of programming, I am looking at some concise explanation for implementing non-blocking calls.
Is there any other way of implementing asynchronous APIs , any other library/framework which might help in this?
You basically need to create a multi-threaded (or multi-process) application. The f1() API needs to spawn a thread (or process) to process the data in a separate execution space. When it completes, the f1() routine needs to signal the main process that the execution is done (signal(), message queues, etc).
A popular way to do asynchronous programming in a plain C programs is to use an "event loop". There are numerous libraries that you could use. I suggest to take a look at
glib.
Another alternative is to use multiple pre-emptive threads (one for each concurrent operation) and synchronize them with mutexes and condition variables. However, pre-emptive threading in plain C is something I would avoid, especially if you want to write portable programs. It's hard to know which library functions are re-entrant, signal handling in threaded programs is a hassle, and in general C libraries and system functions have been designed for single-threaded use.
If you're planning to run your application only on one platform (like Windows) and the work done with f1() is a relatively simple thing, then threading can be OK.
If the function f1() which you are referring to is not itself implemented in a asynchronous fashion, you will need to wrap it up in its own thread yourself. When doing this, you need to be careful with regards to side effects that may be caused by that particular function being called. Many libraries are not designed in a thread-safe way and multiple concurrent invocations of functions from such libraries will lead to data corruption. In such cases, you may need to wrap up the functionality in an external worker process. For heavy lifting that you mention (8-10 seconds) that overhead may be acceptable. If you will only use the external non-threadsafe functions in one thread at a time, you may be safe.
The problem with using any form of event-loop is that an external function which isn't aware of your loop will never yield control back to your loop. Thus, you will not get to do anything else.
Replace delegates with pointers to functions in C, everything else is basically same to what you have read.
Well. Basically I've seen 2 types of async API:
Interrupt. You give a call a callback which should be performed after the call. GIO (part of previously mentioned GLib) works in such a way. It is relatively easy to program with but you usually have the thread in which the callback will be run changed (except if it is integrated with the main loop as in the case of GIO).
Poll. You check if the data is available. The well-known BSD Sockets operate in such a manner. It has an advantage of not necessarily being integrated with the main loop and running callback in a specific thread.
If you program for Gnome or Gtk+-based I'd like to add that GTask seems to be a very nice (potentially nice? I haven't used it). Vala will have better support for GIO-like async calls.