- 2011.05.05 15:03 "[Tiff] Access Violation on TiffClose()", by Katerina Sedivy
- 2011.05.05 17:42 "Re: [Tiff] Is LibTiff 3.9.5 Thread Safe ?", by Frank Warmerdam
2011.05.05 16:44 "[Tiff] Is LibTiff 3.9.5 Thread Safe ?", by Katerina Sedivy
Hi,
So I have my LibTiff.dll 3.9.5 compiled and loaded in a multithread
environement.
I have a tiff which I have used with the TiffInfo tool at command line to
see its information (I've attached the file):
TIFF Directory at offset 0x3e30 (15920)
Subfile Type: (0 = 0x0)
Image Width: 1224 Image Length: 576
Resolution: 96, 96 pixels/inch
Bits/Sample: 1
Compression Scheme: LZW
Photometric Interpretation: min-is-black
Orientation: row 0 top, col 0 lhs
Samples/Pixel: 1
Rows/Strip: 80
Planar Configuration: single image plane
Predictor: none 1 (0x1)
I successfully retrieve the information with this code:
procedure TMainAppRunnerDlg.Button3Click(Sender: TObject);
var
l_Tiff: pointer;
lu_BitsPerSample: Word;
begin
l_Tiff := DLL_TIFFOpen(PChar('C:\cheque_3533_A.tif'), 'r');
if l_Tiff <> nil then
begin
lu_BitsPerSample := 0;
if DLL_TIFFGetField(l_Tiff, 258, lu_BitsPerSample) = 0 then //
TIFFTAG_BITSPERSAMPLE = 258
if lu_BitsPerSample = 0 then
OutputDebugString(PChar('WARNING: TIFFGetField returned false and
BitsPerSample = 0'))
else
OutputDebugString(PChar('WARNING: TIFFGetField returned false and
BitsPerSample <> 0 '));
DLL_TIFFClose(l_Tiff);
outputdebugstring(PChar('Pass!!!'));
end;
end;
BUT This same file failed in a multithread environement. I run the code
below in a Thread. There are 3 threads created which each execute
TIFFGetField multiple times, once in a while BitsPerSample returned by
TIFFGetField is 0 instead of 1.
I also got this message in my debugger for the Tiff file attached:
ODS: module: TIFF directory is missing required "%s" field | message:
C:\Develop\Tests\Service app\Thread1\cheque_3533_A.tif Process
ServiceTester.exe ($A50)
Which is a warning output by TIFFReadDirectory in tif_dirread.c.
procedure TServiceThread.Execute;
var
i: Integer;
l_Config: TConfig;
l_Filenames: TStringList;
ls_Filename,ls_otfilename, ls_dir: string;
lh_ProcRefrence: longint;
lu_BitsPerSample: Word;
lh_TiffHandle: Pointer;
lh_DLLHandle: Cardinal;
begin
CoInitialize(nil);
FreeOnTerminate := True;
l_Filenames := TStringList.Create;
try
LoadConfig(l_Config.InPath, l_Config.FileType, l_Config.Output);
GetFilesToProcess(l_Filenames, l_Config.InPath, l_Config.FileType);
for i := 0 to l_Filenames.Count - 1 do
begin
try
ls_Filename := l_Config.InPath + l_Filenames.Strings[i];
lh_ProcRefrence := DLL_TIFFSetErrorHandler(@TiffErrorProc);
if lh_ProcRefrence = 0 then
begin
OutputDebugString(PChar('WARNING: DLL_TIFFSetErrorHandler
failed'));
exit;
end;
// OutputDebugString(PChar(Format('Thread: %d | File:
%s',[ThreadID, ls_Filename])));
lh_TiffHandle := nil;
lh_TiffHandle := DLL_TIFFOpen(ls_Filename, 'r');
lu_BitsPerSample := 0;
if DLL_TIFFGetField(lh_TiffHandle, 258, lu_BitsPerSample) = 0
then // TIFFTAG_BITSPERSAMPLE = 258
if lu_BitsPerSample = 0 then
OutputDebugString(PChar(Format('WARNING: TIFFGetField
returned false and BitsPerSample = 0 | Filename: %s |ThreadID:
%d',[ls_Filename, ThreadID])))
else
OutputDebugString(PChar(Format('WARNING: TIFFGetField
returned false and BitsPerSample <> 0 | ThreadID: %d',[ThreadID])));
if lh_TiffHandle <> nil then
DLL_TIFFClose(lh_TiffHandle);
except
on E: Exception do
begin
OutputDebugString(PChar(Format('ERROR: %s with file: %s |
ThreadID: %d',[E.Message, ls_Filename, ThreadID])));
exit;
end;
end;
end;
finally
l_Filenames.Free;
CoUninitialize;
FreeLibrary(lh_DLLHandle);
end;