Использование WinAPI волокон с Java

Я делаю Java-привязки для игры, которая использует волокна для своей игровой логики. Пример кода того, как в идеале должны работать скрипты:

public static void main(String[] args) {

    System.out.println("player: " + PlayerId());

    NativeCaller.registerAdditionalThread(() -> {
        while(true) {
            try {
                int player = PlayerId();
                int ped = PlayerPedId();
                Vec3 pos = GetEntityCoords(ped, true);

                System.out.println("ped: " + ped);
            }
            catch (Error e) {
                e.printStackTrace();
            }
            NativeCaller.wait(1000);
        }
    });
}

Вы можете видеть, что есть wait Функция ( см. реализацию) в цикле, который делает что-то. Это не блокировка, это означает, что он приостановит выполнение и возобновит его через некоторое время на другом волокне (и, возможно, потоке).

Проблема в том, что когда блок try-catch выполняется в первый раз, он выдает IllegalMonitorStateException, Второй раз он работает просто отлично. Я заметил, что это происходит только тогда, когда есть класс, который нужно решить. Вы можете видеть, что я использую Vec3 учебный класс. Если я использую два или более классов, он выдаст одно и то же исключение два или более раз, прежде чем наконец выполнится.

Реализация registerAdditionalThread:

JNIEXPORT jlong JNICALL impl_registerAdditionalThread(JNIEnv* env_, jobject obj, jobject runnable) {
    struct task_t {
        jobject runnableTask;
        void(*func)();
    };
    static stack<task_t> runnables;

    void(*func)() = []() {
        task_t task = runnables.top();
        runnables.pop();

        JNIEnv* localEnv;
        jint res = javaVM->GetEnv((void**)&localEnv, JNI_VERSION_1_8);
        jclass runnableCls = localEnv->GetObjectClass(task.runnableTask);
        jmethodID mthdRun = localEnv->GetMethodID(runnableCls, "run", "()V");
        localEnv->CallVoidMethod(task.runnableTask, mthdRun);
        localEnv->DeleteGlobalRef(task.runnableTask);

        DEBUGPRINT("Additional script thread terminated");
    };

    runnables.push({
        env_->NewGlobalRef(runnable),
        func
    });

    scriptRegisterAdditionalThread(GetCurrentModuleHandle(), func);
    return (jlong)func;
}

Я предполагаю, что это потому, что вся эта информация монитора хранится где-то внутри в локальном хранилище потока, и теряется при изменении потока.

Можно ли вообще сделать wait работать как задумано?

0 ответов

Другие вопросы по тегам