RFC 16:OGR线程安全

作者:弗兰克·温特丹

联系方式:warmerdam@pobox.com

现状:发展

总结

为了更好地支持OGR中的线程安全,在更新内部基础结构时添加了一些方法。

定义

可重入 :可重入函数可以由多个线程同时调用,前提是函数的每次调用都引用唯一的数据。

Thread-safe :当每次调用引用共享数据时,多个线程可以同时调用线程安全函数。对共享数据的所有访问都被序列化。

目标

使所有OGR核心和选定的驱动程序可重入,并使驱动程序注册器、驱动程序和数据源至少具有潜在的线程安全性。

测试能力()

将扩展驱动程序和数据源上的TestCapability()方法,以包括在特定实例上测试可重入性和线程安全性的方法。将添加以下宏:

#define OLCReentrant    "Reentrant"
#define ODsCLayerClones "LayerClones"
#define ODsCReentrant   "Reentrant"
#define ODsCThreadSafe  "Threadsafe"

含义:

  • OLCReentrant:层类是可重入的。多个线程可以在这个类的不同实例上操作,包括单个数据源上的不同层。

  • ODsCReentrant:数据源类是可重入的。多个线程可以在这个类的不同实例上操作。

  • ODsCThreadSafe:数据源类是线程安全的。多个线程可以在这个类的单个实例上操作。

  • ODsCLayerClones:支持OGRDataSource::GetLayerClone()方法,并返回一个状态与GetLayer()返回的默认层不同的层实例。

请注意,只要层特征读取状态隐含在层对象中,则单个层实例就不能是线程安全的。所有测试值的默认返回值都是FALSE,这对于TestCapability()方法来说是正常的,但是在确定驱动程序数据源或层实际上是可重入的和/或线程安全的之后,特定的驱动程序可以返回TRUE。

OGRSFDriverRegistrar

为了使驱动程序注册器线程安全,已经进行了各种更改,主要是通过使用互斥锁保护对它的操作。

OGRSFDriver

为了线程安全,不需要对OGRSFDriver基类进行任何更改,主要是因为它几乎什么也不做。

OGRDataSource

该类已被修改为包含m_hMutex类数据成员,该成员是一个互斥体,用于确保对内部数据结构(如层列表)的线程安全访问。当需要独占性时,从OGRDataSource派生的希望实现线程安全操作的类应使用此互斥锁。

将向此类中添加一个新方法:

OGRLayer *GetLayerClone( int i );

此方法的默认实现返回空值。如果数据源的ODsCLayerClones功能为true,则此方法必须返回具有不同特征读取状态的请求层的副本。也就是说,它们可以有自己的空间和属性过滤器设置,内部特性迭代器(用于GetNextFeature()和ResetReading())与其他引用相同底层数据源层的OGRLayer实例不同。

此方法在多线程上下文中的目的是,不同线程可以具有具有不同读取状态的层的克隆。一种可怜的人线程安全,尽管事实上它只是重新进入。

GetLayerClone()返回的层应该与OGRDataSource::ReleaseResultSet()方法一起释放,这与ExecuteSQL()返回的层非常相似。

执行SQL()

OGR datasource::ExecuteSQL()的默认OGR实现在内部使用并修改层状态(特性迭代器和过滤器),因此不适合在试图实现线程安全的数据源上使用,即使可以理解个别层不是线程安全的。

建议的解决方案是,如果数据源支持GetLayerClone(),则将修改此代码以使用GetLayerClone()。

测试

多线程C++测试工具将被用于对支持重新进入和线程安全的数据源进行只读应力测试。

回归测试套件(gdalautotest)中不会包含对可重入性和线程安全性的测试,因为它看起来并不实用。

实施

frankwartemdam将为GDAL/OGR 1.5.0版本实现这个RFC的所有核心特性。此外,Shapefile、Personal Geodatabase、ODBC和Oracle驱动程序将实现OLCReentrant、ODsCLayerClones、ODsCReentrant和ODsThreadSafe。