并行测试与 geos 的交集时出现段错误
Segfault when testing the intersection with geos in parallel
我正在使用 GEOS 的 C API 来管理并行模拟器中的几何图形:我需要确保对象位于受限区域内。
为此,当我的对象迈出一步时,我检查其先前位置和当前位置之间的 line
是否与环境边界相交(environment_manager_->get_border()
,其中 returns a const GEOSPreparedGeometry*
).
代码是 运行 与多个 OpenMP 线程并行。我在通过
开始模拟之前初始化了 GEOS
initGEOS_r(notice, log_and_exit);
context_handler_ = GEOS_init_r();
所以我只有一个处理程序来处理所有线程。
当 运行 使用多个线程进行模拟时,如果我不将 GEOSPreparedIntersects_r
包装在临界区中,代码会在 env_intersect
内部崩溃并出现段错误。
bool SpaceManager::env_intersect(const GEOSGeometry * line) const
{
bool intersect;
// #pragma omp critical // adding prevents segfault
// {
intersect = GEOSPreparedIntersects_r(
context_handler_, environment_manager_->get_border(), line);
// }
return intersect;
}
有人可以指出我做错了什么吗?是否需要以不同方式完成 GEOS 的初始化才能与 OpenMP 一起使用?它是否来自 environment_manager_
是 unique_ptr
的事实? None 个?
段错误的回溯给出:
Thread 19 "python" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffd63da700 (LWP 4374)]
0x00007ffff78816b2 in tcache_get () from /usr/lib/libc.so.6
(gdb) bt
#0 0x00007ffff78816b2 in tcache_get () at /usr/lib/libc.so.6
#1 0x00007ffff5dbf0a9 in operator new(unsigned long) (sz=sz@entry=32)
at /build/gcc-multilib/src/gcc/libstdc++-v3/libsupc++/new_op.cc:50
#2 0x00007fffc8468273 in geos::geom::LineString::computeEnvelopeInternal() const (this=0x555555f10170) at LineString.cpp:278
#3 0x00007fffc845b95f in geos::geom::Geometry::getEnvelopeInternal() const (this=0x555555f10180) at Geometry.cpp:276
#4 0x00007fffc84612ad in geos::geom::GeometryCollection::computeEnvelopeInternal() const (this=0x555555f15980) at GeometryCollection.cpp:257
#5 0x00007fffc845b95f in geos::geom::Geometry::getEnvelopeInternal() const (this=0x555555f15998) at Geometry.cpp:276
#6 0x00007ffff53cea66 in geos::geom::prep::BasicPreparedGeometry::envelopesIntersect(geos::geom::Geometry const*) const () at /usr/lib/libgeos-3.6.2.so
#7 0x00007ffff53cef82 in geos::geom::prep::PreparedLineString::intersects(geos::geom::Geometry const*) const () at /usr/lib/libgeos-3.6.2.so
#8 0x00007ffff5907380 in GEOSPreparedIntersects_r ()
at /usr/lib/libgeos_c.so.1
#9 0x00007ffff61d7938 in growth::SpaceManager::env_intersect(GEOSGeom_t const*) const (this=0x555555fb3b78, line=0x7fff7c045c20)
[编辑] 为每个 OMP 线程制作一个 const GEOSPreparedGeometry*
环境副本并仅访问线程特定副本成功防止了 critical
部分。代码变为:
intersect = GEOSPreparedIntersects_r(
context_handler_, environment_manager_->get_border(omp_id), line);
其中 environment_manager_->get_border(omp_id)
returns 线程特定 const GEOSPreparedGeometry*
。这意味着问题出在我之前使用单个指针时对共享数据的并发访问。这看起来很奇怪,因为该函数应该是线程安全的...
显然线程安全的实现还没有准备好(参见 mailing list exchange)。
我通过在每个线程上使用全局环境几何的副本解决了这个问题(这显然也允许完全并发测试)。
我正在使用 GEOS 的 C API 来管理并行模拟器中的几何图形:我需要确保对象位于受限区域内。
为此,当我的对象迈出一步时,我检查其先前位置和当前位置之间的 line
是否与环境边界相交(environment_manager_->get_border()
,其中 returns a const GEOSPreparedGeometry*
).
代码是 运行 与多个 OpenMP 线程并行。我在通过
开始模拟之前初始化了 GEOSinitGEOS_r(notice, log_and_exit);
context_handler_ = GEOS_init_r();
所以我只有一个处理程序来处理所有线程。
当 运行 使用多个线程进行模拟时,如果我不将 GEOSPreparedIntersects_r
包装在临界区中,代码会在 env_intersect
内部崩溃并出现段错误。
bool SpaceManager::env_intersect(const GEOSGeometry * line) const
{
bool intersect;
// #pragma omp critical // adding prevents segfault
// {
intersect = GEOSPreparedIntersects_r(
context_handler_, environment_manager_->get_border(), line);
// }
return intersect;
}
有人可以指出我做错了什么吗?是否需要以不同方式完成 GEOS 的初始化才能与 OpenMP 一起使用?它是否来自 environment_manager_
是 unique_ptr
的事实? None 个?
段错误的回溯给出:
Thread 19 "python" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffd63da700 (LWP 4374)]
0x00007ffff78816b2 in tcache_get () from /usr/lib/libc.so.6
(gdb) bt
#0 0x00007ffff78816b2 in tcache_get () at /usr/lib/libc.so.6
#1 0x00007ffff5dbf0a9 in operator new(unsigned long) (sz=sz@entry=32)
at /build/gcc-multilib/src/gcc/libstdc++-v3/libsupc++/new_op.cc:50
#2 0x00007fffc8468273 in geos::geom::LineString::computeEnvelopeInternal() const (this=0x555555f10170) at LineString.cpp:278
#3 0x00007fffc845b95f in geos::geom::Geometry::getEnvelopeInternal() const (this=0x555555f10180) at Geometry.cpp:276
#4 0x00007fffc84612ad in geos::geom::GeometryCollection::computeEnvelopeInternal() const (this=0x555555f15980) at GeometryCollection.cpp:257
#5 0x00007fffc845b95f in geos::geom::Geometry::getEnvelopeInternal() const (this=0x555555f15998) at Geometry.cpp:276
#6 0x00007ffff53cea66 in geos::geom::prep::BasicPreparedGeometry::envelopesIntersect(geos::geom::Geometry const*) const () at /usr/lib/libgeos-3.6.2.so
#7 0x00007ffff53cef82 in geos::geom::prep::PreparedLineString::intersects(geos::geom::Geometry const*) const () at /usr/lib/libgeos-3.6.2.so
#8 0x00007ffff5907380 in GEOSPreparedIntersects_r ()
at /usr/lib/libgeos_c.so.1
#9 0x00007ffff61d7938 in growth::SpaceManager::env_intersect(GEOSGeom_t const*) const (this=0x555555fb3b78, line=0x7fff7c045c20)
[编辑] 为每个 OMP 线程制作一个 const GEOSPreparedGeometry*
环境副本并仅访问线程特定副本成功防止了 critical
部分。代码变为:
intersect = GEOSPreparedIntersects_r(
context_handler_, environment_manager_->get_border(omp_id), line);
其中 environment_manager_->get_border(omp_id)
returns 线程特定 const GEOSPreparedGeometry*
。这意味着问题出在我之前使用单个指针时对共享数据的并发访问。这看起来很奇怪,因为该函数应该是线程安全的...
显然线程安全的实现还没有准备好(参见 mailing list exchange)。 我通过在每个线程上使用全局环境几何的副本解决了这个问题(这显然也允许完全并发测试)。