swift:每个类实例加载dylib(或线程安全)

时间:2015-07-16 13:08:50

标签: swift fortran dylib

我遇到一个涉及访问外部库的类实例的问题,该外部库本身使用全局变量,并且可以作为单例访问。因此,我希望/必须为每个swift类实例加载一个dylib实例。 让我提前说明一下:这是我在这里的第一篇文章,如果它的质量与观众不符,我道歉。随意纠正我。

应用程序的背景如下:我正在开发一个框架包,它又使用安装在bundle ./Frameworks文件夹中的dylib中的一些函数。 dylib及其依赖项是用Fortran编写的,用gfortran编译。我已经成功实现并测试了dylib对象的c头,用它们创建了一个模块映射,我能够访问fortran函数并在我的swift类中使用它们(在所有地方传递不安全的指针)。架构如下: myClass.swift - > fortranLib.dylib - > (libgfortran.dylib,libquadmath.dylib)

我遇到的问题是:fortranLib.dylib的实现是一种非常典型的fortran方式 - 它使用全局变量和嵌套函数调用,因此从myClass的多个实例调用它是完全不安全的。当我有一个实例并使用setup_(某些指针)例程初始化fortran库时,一切都按预期工作。一旦我创建myClass的第二个实例并尝试从第二个实例调用setup_()和其他函数,奇怪的事情就会开始发生。这对我来说当然是完全合乎逻辑的:myClass的快速实例都试图访问相同的库函数,不知道库的全局变量和内部交互。

我的问题是:如何通过为myClass的每个实例加载一个全新的fortranLib.dylib来解决这个问题,就像实例和库是独立的内存包一样?

提前谢谢!

1 个答案:

答案 0 :(得分:0)

我想添加我当前的实现,以防它帮助某人。我还没有找到任何方法来加载dlopen或类似的dylibs。
所以我目前的迅速实施如下:

public class MyClass {
   // I create a serial queue for the fortran calls
   // to ensure that they all execute in sequence
   private static let serialFortranQueue = dispatch_queue_create("someName", DISPATCH_QUEUE_SERIAL)
   internal let uuid = NSUUID().UUIDString  // each instance get's an unique id
   internal static var lastUuid = String()  // and the last id to access the fortran library is saved
   // all pointers to fortran are declared in the instance 
   private var someP:UnsafeMutablePointer<Int32> = UnsafeMutablePointer<Int32>.alloc(1)

   deinit() {
      // destroy and dealloc all pointers here
      someP.destroy(); someP.dealloc(1)
   }

   internal static func SetupLibrary(callerID:String) {
      // setup the library only if it isn't for the current caller
      if callerID == lastUuid {return}
      // if not setup the instance
      fortranSetupCall_(someOtherP)
      lastUuid = callerID
   }

   public func myFunction() {
      // prepare the pointers
      someP.memory = 1
      // here the fortran calls are executed in the dispatch queue
      // so that there is no risk of simultaneous access
      dispatch_sync(MyClass.serialFortranQueue) {
         MyClass.SetupLibrary(self.uuid)
         myFortranFunc_(someP)
      }
      // evaluate return pointers, etc.
   }
}