OSX: JavaVM, AWT / Swing et éventuellement un blocage

Je suis vraiment nouveau dans la programmation java, donc je m’excuse d’avance si cela ressemble à une question stupide.

J’essaie de créer une application simple écrite en C simple, qui doit créer un JavaVM , puis une nouvelle fenêtre en chargeant du code Java basé sur AWT/Swing .

Suite à cette note technique, j’ai appris que, sous Mac OSX uniquement, JavaVM doit être appelé à partir d’un thread différent du thread principal pour pouvoir créer une interface graphique basée sur AWT.

Par conséquent, dans la fonction main de mon application C, j’ai créé un nouveau thread qui effectue tout, de la création du javaVM à la création de l’interface graphique.

Puisque l’application n’est en réalité pas si simple, je vais en publier une version simplifiée.

fonction principale:

 int main(int argc, char** argv) { // Run-time loading of JavaVM framework void *result; result = dlopen("/System/Library/Frameworks/JavaVM.framework/JavaVM", RTLD_LAZY); if (!result) { printf("can't open library JavaVM: %s\n", dlerror()); } else { printf("library JavaVM loaded\n"); } /* Start the thread that runs the VM. */ pthread_t vmthread; // create a new pthread copying the stack size of the primordial pthread struct rlimit limit; size_t stack_size = 0; int rc = getrlimit(RLIMIT_STACK, &limit); if (rc == 0) { if (limit.rlim_cur != 0LL) { stack_size = (size_t)limit.rlim_cur; } } pthread_attr_t thread_attr; pthread_attr_init(&thread_attr); pthread_attr_setscope(&thread_attr, PTHREAD_SCOPE_SYSTEM); pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); if (stack_size > 0) { pthread_attr_setstacksize(&thread_attr, stack_size); } /* Start the thread that we will start the JVM on. */ pthread_create(&vmthread, &thread_attr, startJava, (void *)&thread_data_struct); pthread_attr_destroy(&thread_attr); pthread_exit(NULL); return 0; } 

Fonction de fil:

 void *startJava(void *jvm_lib) { JavaVMInitArgs args; const char* classpath = getenv("CLASSPATH"); // determine classpath char* classpath_opt = str_printf("-Djava.class.path=%s", classpath); JavaVMOption* option = malloc(sizeof(JavaVMOption) * 2); option[0].optionSsortingng = classpath_opt; option[1].optionSsortingng = str_printf("-verbose:jni"); args.version = JNI_VERSION_1_6; args.nOptions = 2; args.options = option; args.ignoreUnrecognized = JNI_FALSE; // don't ignore unrecognized options fptr_JNI_CreateJavaVM JNI_CreateJavaVM_fp = (fptr_JNI_CreateJavaVM)dl_dlsym(jvm_lib, "JNI_CreateJavaVM"); int result = JNI_CreateJavaVM_fp(&jvm, (void**) &env, &args); free(option); free(classpath_opt); // launch java code jclass init_class = (*env)->FindClass(env, "org/classes/Loader"); jmethodID load_id = (*env)->GetStaticMethodID(env, init_class, "Load", "(Ljava/lang/Ssortingng;Lorg/classes/stuff;J)V"); (*env)->CallStaticVoidMethod(env, init_class, load_id); } 

Code Java: (MISE À JOUR)

 package org.classes; import java.awt.AWTException; import java.awt.Component; import java.awt.Frame; import java.awt.image.BufferedImage; import java.awt.EventQueue; public class Loader { public static void Load(Ssortingng baseDir, Stuff stuff, long nativePointer) { EventQueue.invokeLater(new Runnable() { public void run() { System.loadLibrary("drawingHelperLibrary"); ... ... ... // start test window Frame frame = new Frame(); frame.setSize(640,480); frame.setLocation(50, 50); frame.setVisible(true); } }); } } 

Tout le code ci-dessus s’exécute avec succès, à l’exception de la création de la fenêtre qui provoque un blocage ou un problème similaire, car le terminal rest occupé sans aucune utilisation de la CPU et les deux threads restnt actifs.

Si je commente les lignes concernant la création de la fenêtre, l’application s’exécute avec succès et quitte.

Voici la sortie de jstack:

 Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.4-b02-402 mixed mode): "Attach Listener" daemon prio=9 tid=1040b1800 nid=0x11b888000 waiting on condition [00000000] java.lang.Thread.State: RUNNABLE "Low Memory Detector" daemon prio=5 tid=103806000 nid=0x10b137000 runnable [00000000] java.lang.Thread.State: RUNNABLE "C2 ComstackrThread1" daemon prio=9 tid=103805800 nid=0x10b034000 waiting on condition [00000000] java.lang.Thread.State: RUNNABLE "C2 ComstackrThread0" daemon prio=9 tid=103804800 nid=0x10af31000 waiting on condition [00000000] java.lang.Thread.State: RUNNABLE "Signal Dispatcher" daemon prio=9 tid=103804000 nid=0x10ae2e000 runnable [00000000] java.lang.Thread.State: RUNNABLE "Surrogate Locker Thread (Concurrent GC)" daemon prio=5 tid=103803000 nid=0x10ad2b000 waiting on condition [00000000] java.lang.Thread.State: RUNNABLE "Finalizer" daemon prio=8 tid=10409b800 nid=0x10ac28000 in Object.wait() [10ac27000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on  (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118) - locked  (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159) "Reference Handler" daemon prio=10 tid=10409b000 nid=0x10ab25000 in Object.wait() [10ab24000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on  (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:485) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116) - locked  (a java.lang.ref.Reference$Lock) "main" prio=5 tid=104000800 nid=0x10048d000 runnable [10048a000] java.lang.Thread.State: RUNNABLE at java.lang.ClassLoader$NativeLibrary.load(Native Method) at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1827) - locked  (a java.util.Vector) - locked  (a java.util.Vector) at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1724) at java.lang.Runtime.loadLibrary0(Runtime.java:823) - locked  (a java.lang.Runtime) at java.lang.System.loadLibrary(System.java:1045) at sun.security.action.LoadLibraryAction.run(LoadLibraryAction.java:50) at java.security.AccessController.doPrivileged(Native Method) at sun.awt.NativeLibLoader.loadLibraries(NativeLibLoader.java:38) at sun.awt.DebugHelper.(DebugHelper.java:29) at java.awt.Component.(Component.java:566) at org.classes.Loader.Load(Loader.java:69) "VM Thread" prio=9 tid=104096000 nid=0x10aa22000 runnable "Gang worker#0 (Parallel GC Threads)" prio=9 tid=104002000 nid=0x103504000 runnable "Gang worker#1 (Parallel GC Threads)" prio=9 tid=104002800 nid=0x103607000 runnable "Concurrent Mark-Sweep GC Thread" prio=9 tid=10404d000 nid=0x10a6f0000 runnable "VM Periodic Task Thread" prio=10 tid=103817800 nid=0x10b23a000 waiting on condition "Exception Catcher Thread" prio=10 tid=104001800 nid=0x103401000 runnable JNI global references: 913 

Je ne sais vraiment pas ce que je peux faire de plus. Peut-être que c’est une erreur stupide mais je ne suis pas assez habile avec ce mélange Java-C car c’est la première fois que je le regarde.

UPDATE: J’ai mis à jour le code java (grâce à trashgod) mais cela ne fonctionne toujours pas. Est-ce que je manque quelque chose?

J’ai pu résoudre ce problème en observant comment le projet Eclipse crée ses lanceurs. Comme vous l’avez fait auparavant, vous devez créer un thread distinct pour la machine virtuelle Java, mais la méthode principale doit démarrer CFRunLoop.

Il pourrait y avoir quelques détails supplémentaires pour votre implémentation particulière, mais quelque chose de similaire à cela fonctionne actuellement dans notre cas:

 ... #include  static void dummyCallback(void * info) {} ... ... if (stack_size > 0) { pthread_attr_setstacksize(&thread_attr, stack_size); } CFRunLoopRef loopRef = CFRunLoopGetCurrent(); /* Start the thread that we will start the JVM on. */ pthread_create(&vmthread, &thread_attr, startJava, (void *)&thread_data_struct); pthread_attr_destroy(&thread_attr); CFRunLoopSourceContext sourceContext = { .version = 0, .info = NULL, .retain = NULL, .release = NULL, .copyDescription = NULL, .equal = NULL, .hash = NULL, .schedule = NULL, .cancel = NULL, .perform = &dummyCallback }; CFRunLoopSourceRef sourceRef = CFRunLoopSourceCreate(NULL, 0, &sourceContext); CFRunLoopAddSource(loopRef, sourceRef, kCFRunLoopCommonModes); CFRunLoopRun(); CFRelease(sourceRef); ... 

Vous pouvez regarder à travers l’implémentation Eclipse ici:

http://git.eclipse.org/c/equinox/rt.equinox.framework.git

Suivant cet exemple , vous n’avez pas besoin d’un thread séparé sur le côté C, sauf si vous utilisez Cocoa. Vous devez invokeLater() votre interface graphique Java sur le thread de répartition des événements à l’ aide de invokeLater() .

J’ai le même problème, si je charge ma bibliothèque native avant AWT, il se bloque. La solution consiste à charger la bibliothèque native AWT AVANT de charger ma bibliothèque native.

 ColorModel.getRGBdefault(); //static code in ColorModel loads AWT native library System.loadLibrary("MyLibrary"); //then load your native code 

Cela ne résout pas réellement le problème de l’affiche originale, mais j’ai trouvé son message tout en essayant de résoudre un problème similaire. Dans mon cas, je dois démarrer un programme c ++ et le faire appeler une bibliothèque d’imagerie écrite en Java. Cette bibliothèque utilise des classes awt, je voyais donc le problème d’interblocage, même si je ne créais pas d’interface utilisateur dans le code Java.

De plus, je veux comstackr le même code c ++ sur différentes plates-formes, évitant ainsi d’utiliser Cocoa.

Comme je n’ai pas besoin de créer une interface utilisateur Java, il m’a été utile d’append “-Djava.awt.headless = true” en tant qu’option au jvm lorsqu’il est lancé à partir du code c ++.

Je voulais poster ceci, au cas où quelqu’un d’autre dans une situation similaire trébuche sur ce post à la recherche de réponses.