Opened 11 years ago

Closed 10 years ago

#5101 closed defect (worksforme)

GDALDataset::GetProjectionRef() blocking

Reported by: Kosta Owned by: warmerdam
Priority: normal Milestone:
Component: GDAL_Raster Version: 1.9.2
Severity: normal Keywords:
Cc:

Description (last modified by Kosta)

It seems that the call to GDALDataset::GetProjectionRef() can sometimes block when used in a multi-threaded environment and used on a dataset opened twice and accessed from two different threads for certain datasets. Sample program to reproduce the behavior (sorry for the usage of boost threads):

const char RASTER_FILE[] = "D:/test.tif";

GDALDataset* const ds1 = static_cast<GDALDataset*>(GDALOpen(RASTER_FILE, GA_ReadOnly));
GDALDataset* const ds2 = static_cast<GDALDataset*>(GDALOpen(RASTER_FILE, GA_ReadOnly));

boost::thread thread1([&]() {
    std::cout << "#1: start calling GetProjectionRef() on thread #" << boost::this_thread::get_id() << std::endl;
    ds1->GetProjectionRef();
    std::cout << "#1: GetProjectionRef(): done" << std::endl;
    boost::this_thread::sleep_for(boost::chrono::seconds(30));
    std::cout << "#1: deleting DS" << std::endl;
    delete ds1;
    std::cout << "#1: DS deleted" << std::endl;
});

boost::thread thread2([&]() {
    boost::this_thread::sleep_for(boost::chrono::seconds(10));
    std::cout << "#2: start calling GetProjectionRef() on thread #" << boost::this_thread::get_id() << std::endl;
    ds2->GetProjectionRef();
    std::cout << "#2: GetProjectionRef(): done" << std::endl;
    std::cout << "#2: deleting DS" << std::endl;
    delete ds2;
    std::cout << "#2: DS deleted" << std::endl;
});

thread1.join();
thread2.join();

The call to GetProjectionRef() on the 2nd threads blocks until the 1st datasource object gets deleted by the 1st thread. You can observe the same behavior if you use a copy of the attached GeoTiff and open both datasets from the 2 different files. Maybe that is related to the not-found EPSG code used by the GeoTiff, which then holds on to an internal lock/mutex?

This has been observed on Windows and I haven't checked this with GDAL 1.10 yet...

Attachments (1)

test.tif (911.5 KB ) - added by Kosta 11 years ago.

Download all attachments as: .zip

Change History (5)

by Kosta, 11 years ago

Attachment: test.tif added

comment:1 by Kosta, 11 years ago

BTW, it also doesn't matter if I open the 2 datasets within the 2 threads; I just avoided that in the example to make it a bit shorter...

comment:2 by Kosta, 11 years ago

Description: modified (diff)

comment:3 by Even Rouault, 11 years ago

I don't reproduce with GDAL 1.10. Here's my source (adapted with just GDAL stuff, but CPLCreateJoinableThread() is a new GDAL 1.10 stuff) if you want to test it :

#include <gdal_priv.h>
#include <cpl_multiproc.h>
#include <iostream>

void main1(void *arg)
{
    GDALDataset* ds1 = (GDALDataset*)arg;
    std::cout << "#1: start calling GetProjectionRef() on thread #1" << std::endl;
    ds1->GetProjectionRef();
    std::cout << "#1: GetProjectionRef(): done. Sleeping for 10" << std::endl;
    CPLSleep(10);
    std::cout << "#1: deleting DS" << std::endl;
    delete ds1;
    std::cout << "#1: DS deleted" << std::endl;
}

void main2(void *arg)
{
    GDALDataset* ds2 = (GDALDataset*)arg;
    //std::cout << "#2: before sleep" << std::endl;
    CPLSleep(1);
    std::cout << "#2: start calling GetProjectionRef() on thread #2" << std::endl;
    ds2->GetProjectionRef();
    std::cout << "#2: GetProjectionRef(): done" << std::endl;
    std::cout << "#2: deleting DS" << std::endl;
    delete ds2;
    std::cout << "#2: DS deleted" << std::endl;
}


int main(int argc, char* argv[])
{
	GDALAllRegister();
	
	const char RASTER_FILE[] = "test.tif";

	GDALDataset* const ds1 = static_cast<GDALDataset*>(GDALOpen(RASTER_FILE, GA_ReadOnly));
	GDALDataset* const ds2 = static_cast<GDALDataset*>(GDALOpen(RASTER_FILE, GA_ReadOnly));

	void* t1 = CPLCreateJoinableThread( main1, ds1 );
	void* t2 = CPLCreateJoinableThread( main2, ds2 );
	
	CPLJoinThread(t1);
	CPLJoinThread(t2);

	return 0;
}

The output is :

ERROR 6: EPSG PCS/GCS code 5100 not found in EPSG support files.  Is this a vali
d
EPSG coordinate system?
#1: GetProjectionRef(): done. Sleeping for 10
#2: start calling GetProjectionRef() on thread #2
ERROR 6: EPSG PCS/GCS code 5100 not found in EPSG support files.  Is this a vali
d
EPSG coordinate system?
#2: GetProjectionRef(): done
#2: deleting DS
#2: DS deleted
#1: deleting DS
#1: DS deleted

comment:4 by Even Rouault, 10 years ago

Resolution: worksforme
Status: newclosed

Closed due to lack of feedback from reporter. Reopen if you can provide more elements

Note: See TracTickets for help on using tickets.