Post by Bob FriesenhahnIt 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