Concurrency JNA并发问题

Concurrency JNA并发问题,concurrency,jna,Concurrency,Jna,我正在尝试访问JNA加载的本机(fortran)库(mylib.so)。通过Spark作业以视差方式访问库。到目前为止,我还没有同步方法调用(也没有同步库),因为对共享库的调用是我计算中的瓶颈,它们必须并行运行 我得到以下错误: # A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x00007ffbcb5f8dcd, pid=58569, tid=14070815

我正在尝试访问JNA加载的本机(fortran)库(
mylib.so
)。通过Spark作业以视差方式访问库。到目前为止,我还没有同步方法调用(也没有同步库),因为对共享库的调用是我计算中的瓶颈,它们必须并行运行

我得到以下错误:

# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007ffbcb5f8dcd, pid=58569, tid=140708155152128
#
# JRE version: Java(TM) SE Runtime Environment (8.0_60-b27) (build 1.8.0_60-b27)
*** Error in `/usr/java/jdk1.8.0_60/jre/bin/java': double free or corruption (!prev): 0x0000000001b756d0 ***
*** Error in `/usr/java/jdk1.8.0_60/jre/bin/java': free(): corrupted unsorted chunks: 0x0000000001b75010 ***
*** Error in `/usr/java/jdk1.8.0_60/jre/bin/java': double free or corruption (!prev): 0x0000000001b756d0 ***
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.60-b23 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libc.so.6+0x38dcd]======= Backtrace: =========
======= Backtrace: =========
======= Backtrace: =========
/lib64/libc.so.6(+0x7d053)[0x7ffbcb63d053]
/lib64/libc.so.6(+0x7d053)[0x7ffbcb63d053]
/lib64/libc.so.6(+0x7d053)[0x7ffbcb63d053]
/lib64/libc.so.6(+0x38e90)[0x7ffbcb5f8e90]
/usr/java/jdk1.8.0_60/jre/lib/amd64/server/libjvm.so(+0x5d43f9)[0x7ffbcabba3f9]
/lib64/libc.so.6(+0x38e90)[0x7ffbcb5f8e90]
/lib64/libc.so.6(+0x38eb5)[0x7ffbcb5f8eb5]
/lib64/libc.so.6(+0x38e69)[0x7ffbcb5f8e69]
/lib64/libc.so.6(+0x38eb5)[0x7ffbcb5f8eb5]
  __run_exit_handlers+0x3d
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
/opt/usr/local/lib/mylib.so(for_exit+0x19)[0x7ff9285b0fa9]
/lib64/libc.so.6(+0x38eb5)[0x7ffbcb5f8eb5]
/opt/usr/local/lib/mylib.so(for_exit+0x19)[0x7ff9285b0fa9]
/opt/usr/local/lib/mylib.so(for__once_private+0x27)[0x7ff9285660b7]
/opt/usr/local/lib/mylib.so(for__once_private+0x27)[0x7ff9285660b7]
/opt/usr/local/lib/mylib.so(for__acquire_lun+0x814)[0x7ff92855ea04]
/opt/usr/local/lib/mylib.so(for__acquire_lun+0x814)[0x7ff92855ea04]
/opt/usr/local/lib/mylib.so(for_write_int_fmt+0x9c)[0x7ff92857f83c]
/opt/usr/local/lib/mylib.so(for__acquire_lun+0x814)[0x7ff92855ea04]
/opt/usr/local/lib/mylib.so(for_write_int_fmt+0x9c)[0x7ff92857f83c]
/opt/usr/local/lib/mylib.so(seterr_+0x1c8)[0x7ff928515328]
/opt/usr/local/lib/mylib.so(for_write_int_fmt+0x9c)[0x7ff92857f83c]
/opt/usr/local/lib/mylib.so(seterr_+0x1c8)[0x7ff928515328]
/opt/usr/local/lib/mylib.so(ddl2sf_+0x322)[0x7ff92850eb02]
/opt/usr/local/lib/mylib.so(seterr_+0x1c8)[0x7ff928515328]
/opt/usr/local/lib/mylib.so(entsrc_+0x80)[0x7ff92850edb0]
/opt/usr/local/lib/mylib.so(bspline_+0x52c)[0x7ff92850d66c]
/opt/usr/local/lib/mylib.so(ddl2sf_+0x2e7)[0x7ff92850eac7]
/opt/usr/local/lib/mylib.so(enter_+0x55)[0x7ff92850ecd5]
/opt/usr/local/lib/mylib.so(rspbsp_+0x4a)[0x7ff928523cda]
/opt/usr/local/lib/mylib.so(bspline_+0x52c)[0x7ff92850d66c]
/opt/usr/local/lib/mylib.so(ddl2sf_+0x16d)[0x7ff92850e94d]
/tmp/jna--1845237309/jna4302334124297214663.tmp(ffi_call_unix64+0x4c)[0x7ff92909465c]
/tmp/jna--1845237309/jna4302334124297214663.tmp(ffi_call+0x1d4)[0x7ff929094164]
/opt/usr/local/lib/mylib.so(bspline_+0x52c)[0x7ff92850d66c]
/opt/usr/local/lib/mylib.so(rspbsp_+0x4a)[0x7ff928523cda]
/tmp/jna--1845237309/jna4302334124297214663.tmp(+0x5870)[0x7ff929087870]
/tmp/jna--1845237309/jna4302334124297214663.tmp(Java_com_sun_jna_Native_invokeVoid+0x22)[0x7ff92908a462]
[0x7ffbb5015994]
有人认为本机库不是线程安全的吗?从stacktracke来看,实际问题似乎是
libc.so
,还是我自己的库
mylib.so


如果问题在我自己的库中,是否可以通过创建共享对象的多个物理副本来解决问题,例如,每个线程一个副本?

这通常表示共享库中存在问题或其使用。如果您没有将库设计为线程安全的,那么很可能不是。单个进程无法多次加载本机库,因此没有简单的解决方案。有两条途径:

  • 从本机库中分配多个对象,并为每个java线程分配不同的对象。如果您的本机库在内部使用静态数据结构,则这可能是不可能的
  • 通过公开本机库的类/方法同步对本机库的访问。这样,一次只有一个java线程可以访问它们。然而,根据您的库和用例的不同,这可能对性能没有帮助——所有操作可能仍然在一个地方
  • 使库线程安全。在本机语言中,这可能比Java困难得多。此外,有些算法不太适合并行化
这通常表示您的共享库或其使用中存在问题。如果您没有将库设计为线程安全的,那么很可能不是。单个进程无法多次加载本机库,因此没有简单的解决方案。有两条途径:

  • 从本机库中分配多个对象,并为每个java线程分配不同的对象。如果您的本机库在内部使用静态数据结构,则这可能是不可能的
  • 通过公开本机库的类/方法同步对本机库的访问。这样,一次只有一个java线程可以访问它们。然而,根据您的库和用例的不同,这可能对性能没有帮助——所有操作可能仍然在一个地方
  • 使库线程安全。在本机语言中,这可能比Java困难得多。此外,有些算法不太适合并行化
我已经在做第一点了。第二点当然会导致锁定,因此线程不再并行工作…JNA提供了一个
Native.synchronizedLibrary()
包装器,它有效地实现了#2。如果您从共享库创建多个对象(而不是从多个线程使用同一个对象)那么你真的没有一个可并行化的解决方案。如果是这种情况,我会查看fortran代码,看看使用静态共享数据的代码是否可以重构。如果这是不可能的,那么您将不得不使用technomage@MartinSerrano我现在真的很困惑。我用唯一的名称制作了我的库的多个副本,两个副本都使用JNA在不同的变量中加载。图像加载了两次,但它们似乎仍然共享内存。也就是说,如果我在一个库中修改一个全局变量,那么它在第二个库中也会接受这个值(对于全局变量,我的意思是它们在一个公共块中)。这是意料之中的吗?@RaphaelRoth,是的,那会令人困惑。我想你遇到了这里描述的问题:我已经在做第一点了。第二点当然会导致锁定,因此线程不再并行工作…JNA提供了一个
Native.synchronizedLibrary()
包装器,它有效地实现了#2。如果您从共享库创建多个对象(而不是从多个线程使用同一个对象)那么你真的没有一个可并行化的解决方案。如果是这种情况,我会查看fortran代码,看看使用静态共享数据的代码是否可以重构。如果这是不可能的,那么您将不得不使用technomage@MartinSerrano我现在真的很困惑。我用唯一的名称制作了我的库的多个副本,两个副本都使用JNA在不同的变量中加载。图像加载了两次,但它们似乎仍然共享内存。也就是说,如果我在一个库中修改一个全局变量,那么它在第二个库中也会接受这个值(对于全局变量,我的意思是它们在一个公共块中)。这是意料之中的吗?@RaphaelRoth,是的,那会令人困惑。我认为您遇到了这里描述的问题:您可以复制多个库;每个都需要在磁盘上有一个唯一的映像(从而有一个唯一的名称)。这是值得尝试的两个线程。虽然这是真的,我一般不会认为这是一个可行的方法-它没有真正的规模和相当一个黑客。我用唯一的名称制作了我的库的多个副本,两个副本都使用JNA在不同的变量中加载。图像加载了两次,但它们似乎仍然共享内存。也就是说,如果我在一个库中修改一个全局变量,那么它在第二个库中也会接受这个值(对于全局变量,我的意思是它们在一个公共块中)。这是预期的吗?您可能需要发送一些显式的库加载标志。可以拿很多旗子;默认情况下,JNA在大多数类unix系统上使用
RTLD_LAZY | RTLD_GLOBAL
。您可以通过
库传入显式值。在这种情况下,您可能需要
RTLD\u LOCAL
。您可以制作库的多个副本;每个磁盘上都需要有一个唯一的映像(因此需要一个唯一的名称)