OSX: JavaVM, AWT / Swing и, возможно, тупик - PullRequest
6 голосов
/ 06 января 2012

Я действительно новичок в программировании на Java, поэтому заранее прошу прощения, если это звучит как глупый вопрос.

Я пытаюсь создать простое приложение, написанное на простом C, которое должно создать JavaVM и затем создайте новое окно, загрузив код Java на основе AWT/Swing.

После этого технического примечания. Я узнал, что только в Mac OSX JavaVM должен вызываться из потокаотличается от основного потока для того, чтобы иметь возможность создавать графический интерфейс на основе AWT.

Поэтому в функции main моего приложения C я создал новый поток, который выполняет все, начиная с созданияjavaVM для создания графического интерфейса.

Поскольку приложение на самом деле не так просто, я опубликую упрощенную версию.

основная функция:

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;
}

Функция резьбы:

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].optionString = classpath_opt;
    option[1].optionString = 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/String;Lorg/classes/stuff;J)V");

    (*env)->CallStaticVoidMethod(env, init_class, load_id);
}

Java-код: (ОБНОВЛЕНО)

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(String 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);

              }
       });
     }
}

Весь код вышевыполняется успешно, за исключением создания окна, котороеch вызывает тупик или что-то подобное, так как терминал остается занятым без какой-либо загрузки ЦП, и оба потока остаются живыми.

Если я закомментирую строки, касающиеся создания окна, приложение выполнится успешно и выйдет.

Это вывод из 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 CompilerThread1" daemon prio=9 tid=103805800 nid=0x10b034000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" 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 <7f3001300> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
    - locked <7f3001300> (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 <7f30011d8> (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 <7f30011d8> (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 <7f30010a8> (a java.util.Vector)
    - locked <7f3001100> (a java.util.Vector)
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1724)
    at java.lang.Runtime.loadLibrary0(Runtime.java:823)
    - locked <7f3004e90> (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.<clinit>(DebugHelper.java:29)
    at java.awt.Component.<clinit>(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

Я действительно не знаю, что еще я могу сделать.Может быть, это глупая ошибка, но я не достаточно опытен с этой смесью Java-C, так как я впервые смотрю на нее.

ОБНОВЛЕНИЕ: Я обновил код Java (благодаря trashgod), но он все еще не работает.Я что-то упустил?

Ответы [ 4 ]

7 голосов
/ 13 февраля 2013

Мне удалось решить эту проблему, посмотрев, как проект Eclipse создает свои средства запуска. Вам нужно создать отдельный поток для JVM, как вы это сделали, но основной метод должен запустить CFRunLoop.

Для вашей конкретной реализации могут существовать некоторые дополнительные детали, но в нашем случае в настоящее время работает нечто подобное:

...
#include <CoreServices/CoreServices.h>

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);
...

Вы можете посмотреть реализацию Eclipse здесь:

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

2 голосов
/ 18 мая 2013

У меня та же проблема, если я загружаю свою нативную библиотеку до AWT, то она зависает. Решение состоит в том, чтобы загрузить собственную библиотеку AWT ПЕРЕД загрузкой моей собственной библиотеки.

ColorModel.getRGBdefault(); //static code in ColorModel loads AWT native library
System.loadLibrary("MyLibrary"); //then load your native code
2 голосов
/ 06 января 2012

Следуя этому примеру , вам не нужен отдельный поток на стороне C, если вы не используете Какао.Вам do необходимо создать свой графический интерфейс Java в потоке диспетчеризации событий , используя invokeLater().

0 голосов
/ 11 мая 2016

Это на самом деле не решает проблему оригинального постера, но я нашел его / ее пост, пытаясь решить аналогичную проблему. В моем случае мне нужно запустить программу на c ++, и она должна вызывать библиотеку изображений, написанную на Java. Эта библиотека использует некоторые классы awt, поэтому я видел проблему взаимоблокировки, хотя я не создавал пользовательский интерфейс в коде Java.

Кроме того, я хочу скомпилировать один и тот же код C ++ на разных платформах, поэтому избегал использования Cocoa.

Поскольку мне не нужно создавать пользовательский интерфейс Java, мне удалось добавить «-Djava.awt.headless = true» в качестве опции в jvm, когда он запускается из кода c ++.

Я хотел бы опубликовать это на тот случай, если кто-то в подобной ситуации наткнется на это сообщение в поисках ответов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...