On 22.09.2013 04:06, Ken Been wrote:If the application that uses your library also uses APR directly, it's
> I am considering using a library (serf) built on APR in my own
> library. Since I'm writing a library, I can make no assumptions about
> what the calling program does - it might have multiple threads started
> before it calls my library, and some of those threads might be using APR.
> My library can call apr_initialize, but I can't guarantee that it
> won't conflict with another call to apr_initialize in some other
> thread that I don't control. Since apr_initialize doesn't seem to be
> thread safe, and I don't want to put (what I consider to be) onerous
> requirements on the users of my library, this effectively makes APR
> unusable for me.
already responsible for initializing it in a single-threaded context. If
it doesn't, it's reasonable to require the app to call your library's
init function, which you can easily protect with a spinlock (that you
can implement using APR's atomic functions).
Correct as far as it goes, but incomplete.
> So first, is my analysis correct?
No, that wouldn't be enough. Just making the counter increment in
> And second, if it is, is there some good reason that apr_initialize
> has not been made thread safe? At first glance I think simply making
> "initialized++" an atomic operation should do it,
apr_initialize (and the decrement in apr_terminate) atomic will not
prevent race conditions. If two threads call apr_initialize
simultaneously, one of them could return with the assumption that APR
was initialized, while the second is still running the initialization
code. Hence the requirement that apr_initialize must be called in a
That said, it would still make sense to make the counter itself atomic,
if only to avoid unexpected results on architectures that do not
guarantee atomic reads and writes to word-sized memory locations.
APR doesn't make assumptions about how an application uses it. So it's
> or if not then making the whole function body a critical section. I'd
> be happy to work on a patch, but the fact that this hasn't been done
> makes me suspect there must be a good reason for that.
up to the caller to make sure the initialization happens in a
That said ... the single-threaded initialization requirement isn't as
onerous as all that; it only requires the application to add two lines
of code in its main function (ignoring error handling):
Any non-trivial application will already have a ton of single-threaded
initialization code anyway, so the above will hardly make any difference.
If you don't want to expose the dependency on APR from your library, you
can create your own init function that the application would call
instead, and do the error handling and atexit(...) call from that.