Invoking a non-reagent core shared library from multiple Java threads

I have Java code that calls some native code originally written in Fortran using JNA. (This is a numerical library, and many mathematical people do their coding in Fortran.) It is compiled into a library .so, see below:

I was getting great results with the whole module being tested in my code, but then I tried to use the code from multiple threads, and it all started with an error with strange errors. Then I looked through some material about Fortran re-code and realized that the library I used had the equivalent of some global variables ( SAVEkeywords in Fortran that remember the values ​​of the variables when the function is called again: fortran SAVE statement )

I am currently wrapping library calls in blocks synchronized, but this greatly reduces performance. It seems to me that it will take considerable effort to reorganize the library, which will be reentrant (it has several thousand lines of numerical code, and it is not clear how the values ​​are transferred when executing subroutines.) Does anyone know a better way to work around the problem? My imagination offers ...

  • Is there a way to force each Java thread to load a separate copy of the shared library into memory so that global variables are efficiently thread-local? Is it possible? I'm not sure how direct JNA binding or library binding works, and if there is a way to use it that way.
  • Will it be twisted even if it is called from different VMs? How can I check to make sure?
  • gfortran (gcc) Fortran , ?
  • - Fortran ? RECURSIVE, , -, , , , .
  • ?

, ; , . PITA , .

+5
2

, . , n JNA - , -, - , , .

public class LibraryReplicator<C> {

    final BlockingQueue<C> libQueue;
    final Class<C> interfaceClass;
    final C proxiedInterface;

    @SuppressWarnings("unchecked")
    public LibraryReplicator(URL libraryResource, Class<C> interfaceClass, int copies) throws IOException {
        if (!interfaceClass.isInterface()) 
            throw new RuntimeException(interfaceClass + "is not a valid interface to map to the library.");

        libQueue = new LinkedBlockingQueue<C>(copies);
        this.interfaceClass = interfaceClass;

        // Create copies of the file and map them to interfaces
        String orig = libraryResource.getFile();
        File origFile = new File(orig);
        for( int i = 0; i < copies; i++ ) {
            File copy = new File(orig + "." + i);
            Files.copy(origFile, copy);                     

            C libCopy = (C) Native.loadLibrary(copy.getPath(), interfaceClass);         
            libQueue.offer(libCopy); // This should never fail
        }               

        proxiedInterface = (C) Proxy.newProxyInstance(
                interfaceClass.getClassLoader(), 
                new Class[] { interfaceClass }, 
                new BlockingInvocationHandler());
    }

    public LibraryReplicator(URL libraryResource, Class<C> interfaceClass) throws IOException {
        this(libraryResource, interfaceClass, Runtime.getRuntime().availableProcessors());
    }

    public C getProxiedInterface() {
        return proxiedInterface;
    }

    /*
     * Invocation handler that uses the queue to grab locks and maintain thread safety.  
     */
    private class BlockingInvocationHandler implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
            C instance = null;

            // Grab a copy of the library out of the queue          
            do {
                try { instance = libQueue.take(); }
                catch(InterruptedException e) {}
            } while(instance == null);

            // Invoke the method
            Object result = method.invoke(instance, args);

            // Return the library to the queue
            while(true) {
                try { libQueue.put(instance); break; }
                catch( InterruptedException e ) {} 
            } 

            return result;
        }       
    }

}

:

MvnPackGenz lib = new LibraryReplicator<MvnPackGenz>(
        MvnPackGenz.class.getClassLoader().getResource("mvnpack.so"), 
        MvnPackGenz.class).getProxiedInterface();

( , 12), lib, "" , :

-rw-r--r-- 1 mao mao 50525 Sep 26 13:55 mvnpack.so
-rw-r--r-- 1 mao mao 50525 Sep 26 18:21 mvnpack.so.0
-rw-r--r-- 1 mao mao 50525 Sep 26 18:21 mvnpack.so.1
-rw-r--r-- 1 mao mao 50525 Sep 26 18:21 mvnpack.so.10
-rw-r--r-- 1 mao mao 50525 Sep 26 18:21 mvnpack.so.11
-rw-r--r-- 1 mao mao 50525 Sep 26 18:21 mvnpack.so.2
-rw-r--r-- 1 mao mao 50525 Sep 26 18:21 mvnpack.so.3
-rw-r--r-- 1 mao mao 50525 Sep 26 18:21 mvnpack.so.4
-rw-r--r-- 1 mao mao 50525 Sep 26 18:21 mvnpack.so.5
-rw-r--r-- 1 mao mao 50525 Sep 26 18:21 mvnpack.so.6
-rw-r--r-- 1 mao mao 50525 Sep 26 18:21 mvnpack.so.7
-rw-r--r-- 1 mao mao 50525 Sep 26 18:21 mvnpack.so.8
-rw-r--r-- 1 mao mao 50525 Sep 26 18:21 mvnpack.so.9

https://github.com/mizzao/libmao/blob/master/src/main/java/net/andrewmao/misc/LibraryReplicator.java

+2

, , : .

Unix - .

, ., , unix .

+1

All Articles