[Proj] libproj4 thread safety

Patrick Mézard 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 
> library
> 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 
> returned
> 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 
> libproj4
> but except for the condition at the return of pj_init its value is 
> meaningless
> 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 
> processed.

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 
work correctly.

> 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 
> hyperspace.
> ;-)
>  In addition, the error status of any projection pointer is preserved 
> regardless
> 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 
> processing
> 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.

Patrick Mézard

More information about the Proj mailing list