2012-01-05 17 views
6

私は本当にJavaプログラミングに新しいので、これは愚かな質問のように聞こえる場合は事前にお詫び申し上げます。OSX:JavaVM、AWT/Swing、おそらくデッドロック

私は平文Cで書かれた簡単なアプリケーションを作成しようとしています。平文Cはに基づいてJavaコードをロードして新しいウィンドウを作成し、JavaVMを作成する必要があります。

thisテクニカルノートMac OSXのみで、AWTに基づいてGUIを作成できるようにするには、メインスレッドとは別のスレッドからJavaVMを呼び出す必要があることを知りました。

したがって、私のCアプリケーションのmain機能では、javaVMの作成からGUIの作成まで、すべてを実行する新しいスレッドを作成しました。

このアプリケーションは実際にはあまり簡単ではないので、簡略化したバージョンを投稿します。

主な機能:

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

       } 
     }); 
    } 
} 

すべてO上記のコードは、デッドロックなどを引き起こすウィンドウの作成を除いて、正常に実行されます。これは、端末がCPU使用量なしでビジーのままであり、両方のスレッドが存続しているためです。

ウィンドウの作成に関する行をコメントアウトすると、アプリケーションは正常に実行され、終了します。

これは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のおかげで)を更新しましたが、それでも動作しません。 何か不足していますか?

答えて

7

私はこの問題を、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

+0

チップありがとうございますが、リンクオプションは何に対応していますか? –

+0

OK、ありがとう、私はそれを自分で見つけました: '-framework CoreFoundation' –

2

この後に、exampleは、Cocoaを使用していない限り、C側に別のスレッドは必要ありません。 event dispatch threadにJava GUIを構築する必要があります。invokeLater()を使用してください。

+0

私はsepareスレッドを作成しない場合、エラーが発生します。_Apple AWT Java VMが最初のスレッドでロードされました - AWTを開始できません。 Javaが最初のスレッドで開始されたため、AWTを開始できません。アプリケーションのInfo.plist_にStartOnFirstThreadが指定されていないことを確認します。イベントディスパッチスレッドについては、私はすでに昨日成功していません。たぶん私はいくつかの間違いをしました。あなたが投稿したリンクをさらに読んで、変更されたコードを投稿します。ご回答どうもありがとうございました。 – Andrea3000

+0

私はinvokeLater()を追加するJavaコードを更新しましたが、何も変更されていません。それを間違った方法で実装しましたか? – Andrea3000

+0

私は見ることができません。 "Apple AWT Java VMが最初のスレッドに読み込まれました - AWTを起動できません。悲しいことに、便利な[回避策]はありません(http:// wwwあなたはGUIを起動し、Cをロードすることができます。ライブラリ? – trashgod

2

AWTより前にネイティブライブラリを読み込んだ場合、同じ問題が発生します。解決方法は、ネイティブライブラリをロードする前にAWTネイティブライブラリをロードすることです。

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

これは実際にオリジナルポスターの問題を解決していませんが、同様の問題を解決しようとしたときに、私は彼/彼女のポストを見つけました。私の場合は、C++プログラムを起動し、Javaで記述されたイメージングライブラリを呼び出さなければなりません。そのライブラリはいくつかのawtクラスを使用しているので、JavaコードでUIを作成していなくても、デッドロックの問題が発生していました。

また、異なるプラットフォームで同じC++コードをコンパイルしたいので、Cocoaの使用を避けました。

Java UIを作成する必要はないので、jvmがC++コードから起動されたときにオプションとして「-Djava.awt.headless = true」を追加することができました。

似たような状況の他の誰かがこの記事に答えを探している場合に備えて、私はこれを投稿したかったのです。

+0

もう少し説明できますか? –

関連する問題