ARPACK是线程安全的吗?

7

在用C语言编写的程序中,同时从不同的线程使用ARPACK特征值求解器安全吗?如果ARPACK本身不是线程安全的,是否有与其API兼容的线程安全实现?快速的谷歌搜索没有找到有用的信息,但鉴于ARPACK在大型科学计算中被广泛使用,我会发现需要一个线程安全的稀疏特征值求解器是非常令人惊讶的。

我对Fortran不是很熟悉,所以我使用f2c将ARPACK源代码翻译成了C,似乎有相当多的静态变量。基本上,翻译后的例程中所有的本地变量都是静态的,这意味着库本身不是线程安全的。


谢谢大家,你们都帮了很多忙。如果可能的话,我会接受所有的建议。 - Tamás
4个回答

5
Fortran 77不支持递归,因此符合标准的编译器可以在程序的数据段中分配所有变量;原则上,既不需要堆栈也不需要堆[1]。可能f2c正在执行此操作,如果是这样,那么使程序非线程安全的可能是f2c步骤,而不是程序本身。当然,正如其他人提到的那样,也要检查COMMON块。编辑:还要检查明确的SAVE指令。SAVE表示变量的值应在过程的后续调用之间保留,类似于C中的静态变量。现在,在数据段中分配所有过程局部数据会使所有变量隐式保存,不幸的是,有很多旧代码假定这一点,即使Fortran标准不保证这一点。显然,这种代码不是线程安全的。关于ARPACK,我不能保证任何事情,但ARPACK通常受到高度评价并广泛使用,因此如果它遭受这些尘土飞扬的问题,我会感到惊讶。
大多数现代Fortran编译器确实使用堆栈分配。您可能会更幸运地使用例如gfortran和-frecursive选项来编译ARPACK。
编辑:
[1] 不是因为更有效,而是因为Fortran最初是在堆栈和堆未被发明之前设计的,出于某种原因,标准委员会希望保留在没有堆栈或堆支持的硬件上实现Fortran的选项,一直到Fortran 90。实际上,我猜在今天严重依赖缓存的硬件上,堆栈比访问遍布数据段的过程局部数据更有效率。

谢谢澄清。那么,理论上来说,我在翻译后的C代码中看到的那些静态变量之所以被设置为静态的,只是因为将它们分配到数据段中更有效吗? ARPACK代码中似乎没有COMMON块(至少在ARPACK源代码中快速搜索“COMMON”并未发现),那么可以安全地说ARPACK代码是线程安全的吗?还是说在FORTRAN中有其他非线程安全机制需要我注意? - Tamás
@Tamas:我更新了我的答案,希望能回答你的进一步问题。 - janneb
谢谢,这帮了我很多!记录一下:看起来ARPACK依赖于LAPACK,而LAPACK有相当多的“SAVE”指令。它们似乎存储机器特定的常量,例如在第一次调用“dlamch”时初始化的“EPS”。我猜这不太难摆脱,但看起来ARPACK本身不是线程安全的。 - Tamás
更新:LAPACK 从3.3版本开始似乎完全支持多线程。至少Netlib参考实现是如此。 - Tamás

5
我使用f2c将ARPACK转换为C。每当您使用f2c并且关心线程安全时,必须使用-a开关。这使得局部变量具有自动存储,即基于堆栈的本地变量,而不是静态变量,这是默认设置。
即便如此,ARPACK本身显然不是线程安全的。它使用许多公共块(即全局变量)来保留在调用其函数之间保持状态。如果记忆无误,它使用反向通信接口,这往往导致开发人员使用全局变量。当然,ARPACK可能是在多线程普及之前编写的。
最终,我重新设计了转换后的C代码,以系统地删除所有全局变量。我创建了一些C结构,并逐渐将全局变量移入这些结构中。最后,我将指向这些结构的指针传递给每个需要访问这些变量的函数。虽然我可以只是在需要时将每个全局变量转换为参数,但将它们全部放在结构中更加清晰。
基本上,这个想法是将全局变量转换为局部变量。

1

ARPACK使用BLAC对吗?那么这些库也需要是线程安全的。 我认为您检查f2c可能不是确定Fortran代码是否线程安全的绝对方法,我猜它也取决于Fortran编译器和库。


是的,ARPACK 依赖于 BLAS 和 LAPACK,所以下一步就是检查它们。我并不是说翻译后的 C 源代码中缺少 "static" 就意味着代码本身是线程安全的,但它的存在表明该库可能不是线程安全的。然而,在浏览源代码时,我感觉重写成线程安全的方式并不太难,如果没有人在我之前这样做,我会感到惊讶。 - Tamás
1
我也在想,也许f2c使用某种编译器策略通过生成静态变量,而另一个编译器则会在堆上分配内存。我不懂Fortran,但似乎与C相比,更多的取决于编译器。Fortran没有暴露指针(对吗?),Fortran编译器比C编译器有更多的自由度。 - Prof. Falken

1
我不清楚f2c在翻译Fortran时使用的策略。由于ARPACK是用FORTRAN 77编写的,需要做的第一件事就是检查COMMON块的存在。这些是全局变量,如果使用,代码很可能不是线程安全的。 ARPACK网页http://www.caam.rice.edu/software/ARPACK/上说有一个并行版本 - 似乎那个版本是线程安全的。

Parallel ARPACK 是通过 MPI 进行并行化的,它可能是线程安全的,也可能不是。 - janneb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接