2

ここ数週間問題が発生しており、自分の直感が正しいかどうかを知る必要があります. 私の Android アプリは C++ ライブラリを使用しており、SIGSEGV エラーが時々発生します。

C++ で記述された NetworkThread を取得しました。これは、サーバーから Update オブジェクトを受け取ります。Java で記述された WorkerThread を取得しました。0.5 秒ごとに新しい更新があるかどうかを NetworkThread に尋ねます。

SWIG で生成された JNI ラッパーを使用して、c++ と Java 間の通信を行いました。

NetworkThread には、std::vectorすべての新しい更新を含む があります。

WorkerThread (Java) は、次の行を使用して新しい Update オブジェクトを取得します。

Update u = nwt.nextUpdate();

次に、NetworkThread (c++) で次のコードをトリガーします。

Update NetworkThread::nextUpdate() {
    pthread_mutex_lock(&nwt_mutex);
    pthread_mutex_lock(&inQ_mutex); // RACING CONDITION
    Update c = inQ.front();
    inQ.erase(inQ.begin());
    if (inQ.size() <= QUEUE_SIZE) {
        pthread_cond_broadcast(&inQ_threshold_cv);
    }
    pthread_mutex_unlock(&inQ_mutex);
    pthread_mutex_unlock(&nwt_mutex);
    return c;
}

Update c = inQ.front();はオブジェクトの浅いコピーを作成します (Update は = 演算子をオーバーライドしません)。Updateには他のオブジェクト(およびオブジェクトのベクトル)への参照が含まれているため、これは悪いと思います。

次に、行inQ.erase(inQ.begin());が呼び出され、std::vector のドキュメントから、削除された要素が破棄されます。この時点で、 c 内のオブジェクトとベクトルへの参照は無効になっているということですか?

Update オブジェクトが次の JNI スニペットで Java に送り返された後:

    // Retrieve the current JNIEnv* with the cached JVM
    int status;
    JNIEnv* env;
    bool isAttached = false;

    status = gCachedJVM->GetEnv((void **) &env, JNI_VERSION_1_2);
    if(status < 0) {
        status = gCachedJVM->AttachCurrentThread(&env, NULL);
        if(status < 0) {
            return;
        }
        isAttached = true;
    }

    jmethodID update = env->GetMethodID(gClazzUpdateListenerWrapper, "update", "(J)V"); // J stands for Java long type

    // Call Java method update from jUpdateListener object
    env->CallVoidMethod(jUpdateListener, update, (jlong)(intptr_t)&u); // Pointer as agument, we'll build the Update object in Java

    if (isAttached) {
        gCachedJVM->DetachCurrentThread();
    }

ここで、Java にアドレス (long) を送信し、次のようにオブジェクトを作成します (SWIG で生成されたデフォルトのコンストラクターを使用します)。

    Player p1;

public void update(long ptrUpdate) {
    final Update u = new Update(ptrUpdate, false);
            p1 = u.getEntity(0).toPlayer();
            ...
    }

私のようにこれを行うのは悪い習慣ですか?これを long で行うのは悪いと思いますが、アドレスが割り当てられて有効であれば、問題はないはずですよね?

とにかく、破棄されて収集されたオブジェクトへの参照を使用し続けているためと思われるSIGSEGVエラー(それ以上の情報はありません)が発生するまで、これはうまく機能しているようです。

4

0 に答える 0