2 votes

Garanties JMM sur le réordonnancement dans un try-with-resource & appels JNI

Étant donné l'exemple de code suivant :

 try (AutoClosable closable = new XXX()) {
      o.method1(closable);  
      o.method2();
 }

Est-ce que le modèle de mémoire Java permet à HotSpot de réordonner closable.close() antes de o.method2() ?

J'omets délibérément les détails d'implémentation comme La méthode 1 capture-t-elle des données pouvant être fermées ? dans la première partie de cette question.


Mon cas d'utilisation spécifique est le suivant :

J'ai une bibliothèque C qui peut être résumée comme suit :

static char* value;

void capture(char* ptr){
        value = ptr;
}

int len(void) {
    return strlen(value);
}

Cette bibliothèque native est enveloppée par JNA

interface CApi extends Library {

 static {
   Native.register("test.so", CApi.class)
 }

  void capture(Pointer s);
  int test();
}

Et mon code client original ressemble à quelque chose comme ça :

cApi = Native.loadLibrary("test.so", CApi.class);

byte[] data = Native.toByteArray("foo");
Memory m = new Memory(data.length + 1);
m.write(0, data, 0, data.length);
m.setByte(data.length, (byte)0);

cApi.capture(m);
System.out.print(cApi.len());

Le problème avec cette première version est que m a été allouée par Java et le cycle de vie de cette mémoire est lié à m étant fortement joignable. m n'est plus fortement accessible une fois que capture(m) et la mémoire sera libérée lorsque la GC entrera en action (JNA s'appuie sur finalize pour libérer la mémoire native)

Pour éviter cela, j'ai proposé de sous-classer les JNA Memory d'introduire un AutoClosableMemory . L'idée est que l'utilisation d'une construction try-with-resource indique clairement que la ressource est fortement accessible dans cette portée. Le bonus étant que nous pourrions libérer la mémoire native dès que nous n'en aurions plus besoin plutôt que d'avoir à attendre une GC (hey c'est RAII !).

try (AutoClosableMemory m = [...]) {
  cApi.capture(m);
  cApi.test();
}

Ai-je la garantie que m.close() ne sera jamais invoqué avant cApi.test() et que m est fortement accessible ? Dans ce cas m est capturé par l'API C sous-jacente mais le compilateur Java n'a aucun moyen de le savoir.

4voto

raphw Points 6008

En théorie, la JVM pourrait réordonner les instructions mais le résultat de la méthode doit rester correct. HotSpot ne comprend pas le code natif et afin de garantir l'exactitude, il ne réordonne jamais le code autour des instructions natives.

1voto

Oleg Points 310

Pour un seul thread, il est garanti que tout s'exécute exactement dans le même ordre que dans votre code (toute réorganisation qui se produit ne peut en aucun cas affecter votre programme). Le réordonnancement peut seulement affecter la façon dont les autres threads voient ce qui se passe. Dans votre question, il n'y a qu'un seul thread, donc votre programme est garanti d'invoquer cApi.test() antes de m.close() .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X