Re: Fwd: glib thread create API



Ryan:

Thanks for taking the time to explain all of this.

On Tue, Nov 12, 2013 at 8:39 AM, Ryan Lortie <desrt desrt ca> wrote:
If you call g_thread_self() and this thread-local variable is found to
be empty, then you get a GThread structure whipped-up on the spot and
returned to you.

Right. This is exactly what I suspected was going on. And then the
thread API calls that are problematic are g_thread_unref() and
g_thread_join(). Unref is a problem because the GThread returned from
g_thread_self() has a strangely defined reference count. Join is
mainly a problem because it calls g_thread_unref(). Is there any other
problem in g_thread_join() that I'm failing to consider?

Given the behavior, I'd like to see some small changes made to the
documentation. I'm willing to make them and contribute the changes:

1. For g_thread_new();

Documentation of the behavior of g_thread_new() when called from a
non-glib thread (basically what you have described), most notably
documenting the initial reference count of the newly created thread.

Documentation of the status of the "main" (initial) thread - if I call
glib_thread_new() in main(), do I get back a valid gthread value?

Documentation of how a proxy GThread object for an alien thread should
be correctly retired. If I call g_thread_unref() on it, and the
refcount goes to zero, that should presumably have the effect of
releasing the storage associated with the proxy GThread object, no?

2. For g_thread_join():

Documentation that g_thread_join() must be passed a valid gthread
(i.e. one originally created by g_thread_new), but may be *called*
from a thread that was *not* allocated by g_thread_new().  The problem
here is a main thread not created by glib_thread_new() needs to be
able to join to glib threads that it creates. Which it can obviously
do, but the documentation should make this clear.

3. For g_thread_yield(), glib_thread_exit():

Documentation about whether these can be called from a thread that was
not allocated by glib_thread_new().


I think these doc changes would be useful, and they are merely a
clarification of the current contract. To clarify: the answers need to
be correct for both pthreads and win32 threads (and so forth).


It should be fairly obvious that since you did not use a
GLib API to create a thread then you should not use our API to collect
it, either.

Umm. No, I don't think that's obvious. Or rather, it's obvious, but
given the current limitations on the thread create API it's
problematic. Not so much when viewed from a "pure glib" perspective,
because what you say about the creator tearing down makes sense. The
problem is that *other* packages (e.g. gtk) are built around the glib
thread API, and once a library like that gets called from a non-glib
thread it's anybody's guess what happens. Given that there is no way
to construct a *valid* GThread object from a native thread, there
really isn't a way to resolve the end-to-end problem across library
boundaries.

E.g. I call a library while running on a pthread or a Win32 thread.
That library was built around glib, and at some point it calls
g_thread_exit(). What happens? This may need to be documented in a
platform-specific way.


Would it help if we documented something along the lines of "On
non-Windows systems, the threads created with this API are pthreads?"

That would be an improvement, but it wouldn't really address my
concern for two reasons:

1. I still think I need to build valid GThread objects from native
threads that I created (because I had to work around the current
thread creation API)

2. I also need a way to resolve this on Windows, so addressing the
pthreads question doesn't fully address the issue.

I'd suggest, rather, clarifying the documentation along the lines that
I outlined above.

Oh. And if g_thread_self() can return invalid answers without
signaling, I think the API needs g_thread_is_gthread(), which returns
true IFF the thread was allocated by g_thread_new(). The fact that
this call even warrants consideration kinda illustrates why the
current behavior of g_thread_self() isn't a good thing.

As mentioned, the GThread returned from this API is completely legit.

I don't know how to reconcile this statement with your previous
observations that the resulting GThread cannot be passed to the
GThread APIs. But I *do* now understand why you feel it isn't a big
issue.


But thank you again for walking through this. Thanks to your
explanation, I believe I now see how to accomplish what I need to do.
It's mildly awkward, but only that.


Actually, given your explanation, I think that a very simple change to
the current API would likely suffice for everything I need, and would
be fully portable:

   g_thread_register_cleanup_function(void (*)(GThread));

The idea is to let the application supply a thread tear-down function
that will be called before glib's internal destruction procedure
happens. If this existed, then the rest of the existing API provides
enough that I can keep track of the associations and do the right
thing for glib-alien threads. It is the responsibility of the
application to keep track of which GThreads are glib-alien, and
perform teardown actions only for glib-alien threads.

I can definitely live without it for now, but it seems like this might
resolve the awkward edges of the current implementation, no?


shap


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]