Discussion:
is libtiff thread-safe?
James Xu
2004-11-04 18:31:08 UTC
Permalink
Hi,

Does anyone know if the latest version of libtiff is thread-safe?
I looked all over the internet and couldn't find the answer.
I looked through some of the code and it didn't look thread-safe.

Any help would be appreciated.

Thanks
James
Bob Friesenhahn
2004-11-04 19:04:29 UTC
Permalink
Post by James Xu
Does anyone know if the latest version of libtiff is thread-safe?
I looked all over the internet and couldn't find the answer.
I looked through some of the code and it didn't look thread-safe.
There is clearly code in libtiff which is not thread safe. The
error-reporting mechanism is not thread safe (or is at least
thread-unfriendly).

Bob
======================================
Bob Friesenhahn
***@simple.dallas.tx.us
http://www.simplesystems.org/users/bfriesen
Chris Losinger
2004-11-04 19:09:11 UTC
Permalink
oh?

that's an unpleasant thing to learn.

are there any plans to make it thread safe?
Post by Bob Friesenhahn
Post by James Xu
Does anyone know if the latest version of libtiff is thread-safe?
I looked all over the internet and couldn't find the answer.
I looked through some of the code and it didn't look thread-safe.
There is clearly code in libtiff which is not thread safe. The
error-reporting mechanism is not thread safe (or is at least
thread-unfriendly).
Bob
__________________________
Chris Losinger
Smaller Animals Software, Inc.
http://www.smalleranimals.com
Bob Friesenhahn
2004-11-04 19:19:31 UTC
Permalink
Post by Chris Losinger
oh?
that's an unpleasant thing to learn.
are there any plans to make it thread safe?
There was some discussion on the list (initiated by Joris I think)
regarding proposed improvements to the error reporting APIs to make
them easier to use with threads.

It seems that libtiff is currently thread-agnostic. It doesn't do
anything special to support threads, however, it is not a disaster
either since its implementation is mostly re-entrant.

In some target environments, libtiff should be specially compiled to
ensure that its use of C library APIs (and global errno) is thread
safe. I don't believe that this special compilation support exists
yet.

Bob
Post by Chris Losinger
Post by Bob Friesenhahn
Post by James Xu
Does anyone know if the latest version of libtiff is thread-safe?
I looked all over the internet and couldn't find the answer.
I looked through some of the code and it didn't look thread-safe.
There is clearly code in libtiff which is not thread safe. The
error-reporting mechanism is not thread safe (or is at least
thread-unfriendly).
Bob
__________________________
Chris Losinger
Smaller Animals Software, Inc.
http://www.smalleranimals.com
_______________________________________________
Tiff mailing list
http://xserve.flids.com/mailman/listinfo/tiff
======================================
Bob Friesenhahn
***@simple.dallas.tx.us
http://www.simplesystems.org/users/bfriesen
Joris
2004-11-04 21:10:44 UTC
Permalink
Post by Bob Friesenhahn
It seems that libtiff is currently thread-agnostic. It doesn't do
anything special to support threads, however, it is not a disaster
either since its implementation is mostly re-entrant.
There's a concept self-threading that some use, that seems to mean objects
encapsulating all needed synchronization, such that any number of threads may do
anything with that object at any one time.

Another common flavor of meaning of the word 'thread-safe' is that any number of
threads are allowed to use a library at any one time, but the application should
make sure that the single same 'object' (or TIFF *, or whatever has similar
functionality) can only be used by one thread at any one time. Meaning,
essentially, add a critical section or mutex, per main 'object', or some
particular application logic, and no problem.

Some libraries claim to be thread-safe, and next go on to document
initialization and finalization functions that both must be called only once.
That means these functions cannot be called by all threads independently, that
extra application logic is needed (eg embedding initialization and finalization
inside single main thread at application initialization and finalization time),
or that extra synchronization is needed (eg a critical section or mutex that
protects a flag that signals whether initialization is done,...).

My point: the word 'thread-safe' applied to any library, is mostly non-sence.
Speaking of anything beyond the most atomic bit of data, there is no such
concept as a simple bilevel thread-safeness. Instead, we should try to figure
out what rules exactly need to be respected to use LibTiff in a thread-safe
fashion, what issues exactly there are.

Here's an attempt at starting that, but I don't claim to be absolutely certain
about anything.

** Error handling **

Bob pointed out error handling may be a problem. My personal opinion is that
error handling is a problem, but the problem is not multi-threading related. The
LibTiff error and warning handlers don't receive any indication as to what
particular TIFF * the errors and warnings apply to. That is a problem in any
application that uses multiple TIFF *. I've come to the conclusion that most
LibTiff users that have this problem, simply avoid it by ignoring errors and
warnings on that end, and only check return values of the LibTiff calls. The
price they have to pay is that they have no text description of what error
happened exactly, and also they cannot have any meaninfull handling of warnings
at all. 'The file could not be opened because an error occured while opening the
file.'

The problem is not multi-threading related, in that it is not any different
whether you use a single thread or lots of them. On the contrary, the use of
multiple threads may actually ease the problem a bit, as Bob pointed out when
this was discussed a while ago, since in the particular case that an application
uses no more then one TIFF * per thread, threadvars can be used for the pointers
to error and warning handlers, and thus the situation becomes the same as if
there were only a single TIFF * and text descriptions of errors and warnings can
be 'localized', associated to the correct TIFF *.

** RGBA interface and in particular color convertion initialization **

This may or may not be a problem, I'm not knowledgable on this subject. In
particular, LibTiff may or may not be building some LUTs, and it may be so that
it holds on to these LUTs once they are build. In that case, there may be a
problem. But I wouldn't know.

** Using the TIFF *, above mentioned issues aside **

I believe only one thread should access a TIFF * at the same time. This should
be a consequence of application logic, or should be ensured by protecting access
to any TIFF * with a critical section or mutex per TIFF *. Under this condition,
I believe there is no problem.

** Example of thread-safe usage **

Suppose the application ignores error and warning text description, ie the
handlers are dead ends, and the application merely checks return values to see
if an error occurs. Furthermore assume that the application does not use the
RGBA series of functions, uses the strip/tile interface instead, and assumes
responsability for handling any needed color convertion outside of LibTiff.

If such an application has worker threads. Each thread independently opens a
TIFF file, and extract tag values and raster data, does some operation to it,
storing the result in a raster object, closes the TIFF file, and posts the
raster object result to the main thread for display.

Meaning, there are different threads, each uses the LibTiff library and owns one
or more TIFF *; but no single TIFF * is used in multiple threads at the same
time, by application design.

I believe that is absolutely safe.

** Example of threading problem **

Suppose a similar application wants to use a similar scheme of different
threads, but each is working on a different page in a single TIFF *.

I believe LibTiff design is not suitable to meet this need directly. Instead,
the application should be designed such that each thread openes, manages and
eventually closes its own TIFF *, even if all these TIFF * access the same file.

** How that threading problem can be important **

So here I am buying a quadruple processor, thinking I'll be able to decode a
tiled TIFF four times as fast because each processor can simultaniously work on
its own tile.

Wrong. Such a scheme will involve at least four TIFF *. All of these have to be
initialized (opening = opening + reading first IFD + jumping to desired IFD and
reading that one). Chances are this overhead is quite big compared to the
decoding of a tile...

** How, hypothetically, another LibTiff design could do better **

Another LibTiff design could have been to not use the same object for both
global file stuff handling, particular IFD handling, and particular thread
handling. Instead, a TIFF codec library could be designed with dedicated objects
for each of these. A file object could support 'spawning' any number of IFD
objects, and IFD object could support 'spawning' any number of tile objects.
Above quadruple processor design could then actually work quite well.

** Bottom line **

There is no single short answer to this question, there is no such thing as a
simple bilevel thread-safeness concept. Instead, both application and LibTiff
design should be analyzed to see if/how it works, if it is in need of some extra
synchronization handling or a little detour such as using multiple TIFF * on the
same file, or whatever. In other words: an application specific discussion will
be needed, there is no universal answer.



Joris Van Damme
***@awaresystems.be
http://www.awaresystems.be
Download your free TIFF tag viewer for windows here:
http://www.awaresystems.be/imaging/tiff/astifftagviewer.html
Chris Losinger
2004-11-04 21:20:34 UTC
Permalink
Joris,

Thanks for the information.

My particular situation requires the ability to handle multiple
threads, each having their own TIFF*, all possibly using the RGBA
interfaces for reading. And, from your deescription, it sounds like
everything should be OK, *if* the RGBA stuff is able to handle multiple
threads, each with their own TIFF*.

I'll look into it myself, but if you or anyone has any specific
info on the RGBA stuff, I'd appreciate hearing it.

Thanks again.

-c
Post by Joris
Another common flavor of meaning of the word 'thread-safe' is that any number of
threads are allowed to use a library at any one time, but the application should
make sure that the single same 'object' (or TIFF *, or whatever has similar
functionality) can only be used by one thread at any one time. Meaning,
essentially, add a critical section or mutex, per main 'object', or some
particular application logic, and no problem.
__________________________
Chris Losinger
Smaller Animals Software, Inc.
http://www.smalleranimals.com
Bob Friesenhahn
2004-11-04 21:35:08 UTC
Permalink
Post by Chris Losinger
Thanks for the information.
My particular situation requires the ability to handle multiple
threads, each having their own TIFF*, all possibly using the RGBA interfaces
for reading. And, from your deescription, it sounds like everything should be
OK, *if* the RGBA stuff is able to handle multiple threads, each with their
own TIFF*.
Right, *except* for the warning/error callback interfaces which we
already know have problems since they do not include a pointer to user
context. However, thread-specific data techniques can be used (by the
application) to work-around these particular problems.

Bob
======================================
Bob Friesenhahn
***@simple.dallas.tx.us
http://www.simplesystems.org/users/bfriesen
Chris Cox
2004-11-04 23:09:06 UTC
Permalink
Post by Bob Friesenhahn
Post by Chris Losinger
Thanks for the information.
My particular situation requires the ability to handle
multiple threads, each having their own TIFF*, all possibly using
the RGBA interfaces for reading. And, from your deescription, it
sounds like everything should be OK, *if* the RGBA stuff is able to
handle multiple threads, each with their own TIFF*.
Right, *except* for the warning/error callback interfaces which we
already know have problems since they do not include a pointer to
user context. However, thread-specific data techniques can be used
(by the application) to work-around these particular problems.
Documenting that issue and suggesting that the callbacks contain a
mutex or critical section (if thread safety is an issue) might be a
good idea.

Chris
Joris
2004-11-04 23:51:03 UTC
Permalink
Post by Chris Cox
Documenting that issue and suggesting that the callbacks contain a
mutex or critical section (if thread safety is an issue) might be a
good idea.
I totally fail to see the connection between the lack of TIFF * parameter in the
callbacks on the one hand, and multi-threading on the other. The callbacks are
called in the same thread context as the call to LibTiff in which the error
occured. There's no threading issue here.

Of course, *if* you next want to eg post all errors into the singe main UI
thread or something... but that's
a) a trivial multi-threading issue, as in not specific to warning or error
handlers and totally not specific to these particular handlers,
b) it is an assumption that you would want to post all error feedback to another
thread or do anything else with them that might involve synchronization issues,
as one might as well wish to keep things in a single thread, like eg an
encapsulating TIFF object being owned and maintained in a single thread that
also stores a copy to the error description, and
c) this whole threading issue has nothing to do with the only actual base
problem of the error and warning handlers as they are today, the problem that
makes it impossible to really build on these handlers for whatever purpose,
being the lack of TIFF * indication. The lack of TIFF * means application cannot
trace back to a particular thread, sure, it also means application cannot trace
back to a particular encapsulating TIFF object, or a particular file, or
whatever. It simply means application cannot trace back the context of the
error, and that is an issue in any case beyond the single-app-single-TIFF
situation.

So why is this even raised in relation to multi-threading? It is an issue, sure,
but it is not related.

Put otherwise: sure, if you need to feed errors from different threads to a
single thread, you'll need to do some synchronization thinking. On the totally
other end of the universe, if you maintain a filename string that is accessed
from different threads, you might need to do some trivial synchronization
thinking too. If encoded data production (like eg reception over a socket)
originates from one thread, and a secondary thread decodes, there is a need for
some trivial synchronization thinking. There is no more intrinsic connection
between the error handlers and multithreading, then there is between the
filename maintanance and multithreading, or IO and multithreading. Ie, there is
*no* specific error/warning handler issue when it comes to multithreading.

There *is* a fundamental problem with current handlers, being that they don't
have a clue what TIFF * they apply to, which impairs all sorts of building on
from it.

Joris Van Damme
***@awaresystems.be
http://www.awaresystems.be
Download your free TIFF tag viewer for windows here:
http://www.awaresystems.be/imaging/tiff/astifftagviewer.html
Bob Friesenhahn
2004-11-05 00:40:44 UTC
Permalink
Post by Joris
Post by Chris Cox
Documenting that issue and suggesting that the callbacks contain a
mutex or critical section (if thread safety is an issue) might be a
good idea.
I totally fail to see the connection between the lack of TIFF * parameter in the
callbacks on the one hand, and multi-threading on the other. The callbacks are
In that case I will attempt to educate you.
Post by Joris
called in the same thread context as the call to LibTiff in which the error
occured. There's no threading issue here.
There is a threading issue because the thread which experiences the
error is also the one which would normally make use of the detailed
error information. When the code which invoked a libtiff function
returns, it needs to be able to retrieve the error information so that
it can properly inform the user. That means that the libtiff
warning/error callback must store the error info in some
thread-specific place so that it may be retrieved once the libtiff
function returns. If the functions provided a pointer to user context
then the error information could simply be stored there, without any
need to use an OS-specific thread-API function to support
thread-specific storage.

Bob
======================================
Bob Friesenhahn
***@simple.dallas.tx.us
http://www.simplesystems.org/users/bfriesen
Phillip Crews
2004-11-05 00:53:24 UTC
Permalink
Post by Bob Friesenhahn
Post by Joris
Post by Chris Cox
Documenting that issue and suggesting that the callbacks contain a
mutex or critical section (if thread safety is an issue) might be a
good idea.
I totally fail to see the connection between the lack of TIFF * parameter in the
callbacks on the one hand, and multi-threading on the other. The callbacks are
In that case I will attempt to educate you.
Post by Joris
called in the same thread context as the call to LibTiff in which the error
occured. There's no threading issue here.
There is a threading issue because the thread which experiences the
error is also the one which would normally make use of the detailed
error information. When the code which invoked a libtiff function
returns, it needs to be able to retrieve the error information so that
it can properly inform the user. That means that the libtiff
warning/error callback must store the error info in some
thread-specific place so that it may be retrieved once the libtiff
function returns. If the functions provided a pointer to user context
then the error information could simply be stored there, without any
need to use an OS-specific thread-API function to support
thread-specific storage.
Another issue is that the pointers to the error and warning handlers are
shared by all threads, so different threads cannot set up different
error handling routines for different uses. For compilers and platforms
that support it, this can be remedied easily in tif_win32.c by adding
the appropriate modifier to the definitions (e.g., for win32/VC it's
__declspec(thread)).

Other than that small issue, I have had no problems running libtiff in
an intensive multi-threaded environment.

- Phillip
John Aldridge
2004-11-05 12:19:14 UTC
Permalink
Post by Phillip Crews
Post by Bob Friesenhahn
function returns. If the functions provided a pointer to user context
then the error information could simply be stored there, without any
need to use an OS-specific thread-API function to support
thread-specific storage.
Another issue is that the pointers to the error and warning handlers are
shared by all threads, so different threads cannot set up different
error handling routines for different uses.
How about this for solving both problems in one go...

Extend the TIFF data structure to contain a pair of function pointers to
error and warning handling functions. When an error or warning occurs,
see whether the relevant pointer is NULL, and if so just call the
existing global function. If it's not NULL, then call the function from
the TIFF structure instead, passing the TIFF* as an argument. I guess
there's no need for specific user context for these functions, as the
TIFFGet/SetClientInfo seems to cover it?
--
John
Joris
2004-11-05 12:50:19 UTC
Permalink
Post by John Aldridge
How about this for solving both problems in one go...
Extend the TIFF data structure to contain a pair of function pointers to
error and warning handling functions. When an error or warning occurs,
see whether the relevant pointer is NULL, and if so just call the
existing global function. If it's not NULL, then call the function from
the TIFF structure instead, passing the TIFF* as an argument. I guess
there's no need for specific user context for these functions, as the
TIFFGet/SetClientInfo seems to cover it?
The option to set handlers per TIFF * is not necessary (though, of course, it
doesn't hurt, either).

The only thing really necessary is a TIFF * as an argument to these handlers.
That way, the handlers can indeed retrieve ClientInfo, and thus locate context.

Note that in none of the above the word 'thread' occurs. The assessment of the
problem, and the proposed solution, does not change whether the scheme is
multi-threading or not.

This was all discussed earlier... See http://www.asmail.be/msg0054965642.html
for latest archived discussion, and http://www.asmail.be/msg0054815913.html for
first archived discussion. The best solution proposed in these discussions is
indeed the one you propose here. Passing TIFF * (or even directly ClientInfo) as
an argument to the handlers, is similar to how it is done in LibJpeg, and every
other library I can think of.


Joris Van Damme
***@awaresystems.be
http://www.awaresystems.be
Download your free TIFF tag viewer for windows here:
http://www.awaresystems.be/imaging/tiff/astifftagviewer.html
Chris Cox
2004-11-05 01:06:43 UTC
Permalink
Post by Bob Friesenhahn
Post by Joris
Post by Chris Cox
Documenting that issue and suggesting that the callbacks contain a
mutex or critical section (if thread safety is an issue) might be a
good idea.
I totally fail to see the connection between the lack of TIFF * parameter in the
callbacks on the one hand, and multi-threading on the other. The callbacks are
In that case I will attempt to educate you.
Post by Joris
called in the same thread context as the call to LibTiff in which the error
occured. There's no threading issue here.
There is a threading issue because the thread which experiences the
error is also the one which would normally make use of the detailed
error information. When the code which invoked a libtiff function
returns, it needs to be able to retrieve the error information so
that it can properly inform the user. That means that the libtiff
warning/error callback must store the error info in some
thread-specific place so that it may be retrieved once the libtiff
function returns. If the functions provided a pointer to user
context then the error information could simply be stored there,
without any need to use an OS-specific thread-API function to
support thread-specific storage.
Also, if you want to go the simple route:
printf is not very threadsafe -- it may not crash, but
calling it from multiple threads will rarely do what you expect.

Chris
Joris
2004-11-05 09:19:24 UTC
Permalink
Post by Bob Friesenhahn
Post by Joris
I totally fail to see the connection between the lack of TIFF * parameter in the
callbacks on the one hand, and multi-threading on the other. The callbacks are
In that case I will attempt to educate you.
How fortunate.
Post by Bob Friesenhahn
If the functions provided a pointer to user context
then the error information could simply be stored there, without any
need to use an OS-specific thread-API function to support
thread-specific storage.
My point exactly. In other words, if the function were adequate... there would
be not threading issue, nor any other issue of tracing back the error to its
context, nor any other issue of storing the error description in the right
place. In my view, that means the issue is not threading specific, not threading
related.

Investigating the above quote the other way around now, the functions *not*
providing a pointer to user context, the thread specific storage (threadvars or
whatever) are *not* going to help you if the thread uses multiple TIFF *. It's
still not possible in that case to trace back to user context.

In other words, threading is not related to this issue.


Joris Van Damme
***@awaresystems.be
http://www.awaresystems.be
Download your free TIFF tag viewer for windows here:
http://www.awaresystems.be/imaging/tiff/astifftagviewer.html
Bob Friesenhahn
2004-11-05 14:38:29 UTC
Permalink
Post by Joris
Post by Bob Friesenhahn
If the functions provided a pointer to user context
then the error information could simply be stored there, without any
need to use an OS-specific thread-API function to support
thread-specific storage.
My point exactly. In other words, if the function were adequate... there would
be not threading issue, nor any other issue of tracing back the error to its
context, nor any other issue of storing the error description in the right
place. In my view, that means the issue is not threading specific, not threading
related.
Without threading, using a simple static variable to cache libtiff
warnings/errors is sufficient.
Post by Joris
Investigating the above quote the other way around now, the functions *not*
providing a pointer to user context, the thread specific storage (threadvars or
whatever) are *not* going to help you if the thread uses multiple TIFF *. It's
still not possible in that case to trace back to user context.
Good point. However, in a single-threaded program, only one libtiff
call can be active at a time, so it can still be made to work with
some care.
Post by Joris
In other words, threading is not related to this issue.
Of course threading is related to the issue, but the issues go beyond
threading.

Bob
======================================
Bob Friesenhahn
***@simple.dallas.tx.us
http://www.simplesystems.org/users/bfriesen

Loading...