[Proj] libproj4 thread safety
pmezard at gmail.com
Thu Feb 24 02:59:20 EST 2005
Gerald Evenden wrote:
> Let me ask the question: given a program that is executing libproj4
> members only active at only one point in the program? That are there
> are no
> parallel processes accessing the same memory other than in the context
> of shared libraries? When a process has called an entry point to
> libproj4, then
> any use of global variables would be OK as long as their state was
> to the same condition at return as their state at entry?
> What I am driving at is that pj_errno can be used during execution of
> but except for the condition at the return of pj_init its value is
> at the return of any other entry. Secondly, no other entry to
> libproj4 library
> can be made to libproj4 library entry while another entry is being
Well, you are right about pj_errno. Now, assuming pj_errno is the only
library global variable, and every thread owns a PJ instance, then
calling the library from several threads at the same time is likely to
> These questions may seem dumb, especially a few years ago, but I'm never
> sure that some Star Trek processor is not doing some gee whiz stuff in
> In addition, the error status of any projection pointer is preserved
> of how many executions are made with other projection pointers.
> If paragraph 2 is allowed then current internal actions regarding
> pj_errno can
> remain in place and upon pj_fwd/pj_inv return the projection pointer
> will be updated
> with the contents of pj_errno. IF NECESSARY, pj_errno can be saved
> upon entry
> and restored so that the last return code of a pj_init can be
> recovered. I do not
> think that this is very important. If conditions in this paragraph
> are not acceptable
> then we have a lot of coding to do---or resort to long-jumps.
Once pj_errno is embedded withing PJs, I no longer care about the global
> Lastly: fully functional examples:
> A = pj_init();
> B = pj_init();
> assume A and B not null:
> r1=pj_fwd(A,) // projection fails, contents of r1 HUGE
> r2=pj_fwd(B,) // projection OK, r2 valid
> pj_error(A); // returns negative error code
> pj_error(B); // returns 0 --no error
> Another example:
> r1=pj_inv(A,pj_fwd(B,r1)); // perfectly valid
> If pj_fwd fails pj_error will return error code for both A and B calls;
> the inverse call will fail because of HUGE input.
> If pj_fwd OK but pj_inv fails only A shows error. B OK.
> Note that B could be identical to A (eliminating the second pj_init but
> we would lose the independence of the error checking.
> If the code operates like a forked process except that we are still in
> the same
> process then all bets are off. That is, libproj4 rouitines can only
> one structure at a time handling pj_errno
> It all boils down to what one means by "simultaneous.". I understand how
> multiple processes can function "simultaneously" and be syncronized by
> various means but I do not see how a single process can have multiple
> paths of execution --- if that is what we are talking about?
Exactly, threads are generally called "lightweight processes". They are
execution contexts within a process, with their own stack and some other
stuff, but they share everything else including memory space. So, almost
everything related to threading summarize to memory visibility problems.
When memory is shared in read/write mode, you have to synchronize reads
and writes operations. When memory is shared in read mode only, you may
share it without synchronization primitives. And to avoid
synchronization, do not share memory location, provide one instance per
thread [disclaimer : this is a bit simplistic but I do not want to dive
into threading discussions here, and this model is sufficient in
practice]. This is why I say that if pj_errno is the only global
variable out there, then your library is likely to be thread safe if PJs
are not shared between threads - that is every thread calls pj_init for
every projection it uses.
More information about the Proj