You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JNI库线程等待与Telegram JNI Lib同步调用getChatList()方法

Alright, let's tackle your two JNI synchronization problems—both are about bridging async operations to synchronous calls, which is a common pain point when working with native code and TDLib. Here's a step-by-step breakdown for each:

1. How to Wait for Thread Completion in a JNI Library

There are a few reliable ways to handle this, depending on whether you control the thread creation or are dealing with callback-based async tasks:

Option 1: Use pthread Native Sync (for threads you create)

If you spawn threads directly with pthread_create, the simplest approach is pthread_join to block until the thread finishes:

#include <pthread.h>

void* worker_task(void* arg) {
    // Your thread's logic here (e.g., compute data, call APIs)
    return NULL;
}

JNIEXPORT void JNICALL Java_com_yourpackage_YourClass_waitForThread(JNIEnv* env, jobject thiz) {
    pthread_t worker_thread;
    pthread_create(&worker_thread, NULL, worker_task, NULL);
    
    // Block until the thread completes execution
    pthread_join(worker_thread, NULL);
}

Option 2: Condition Variables (for callback-driven async tasks)

If you're dealing with async operations that notify completion via callbacks (like most SDKs), use a pthread condition variable + mutex to wait for the callback signal:

#include <pthread.h>

// Global sync primitives (wrap in a struct for better encapsulation in production code)
pthread_mutex_t task_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t task_cond = PTHREAD_COND_INITIALIZER;
int task_is_completed = 0;

// Callback triggered when the async task finishes
void on_task_finished() {
    pthread_mutex_lock(&task_mutex);
    task_is_completed = 1;
    pthread_cond_signal(&task_cond); // Notify waiting thread
    pthread_mutex_unlock(&task_mutex);
}

JNIEXPORT void JNICALL Java_com_yourpackage_YourClass_waitForAsyncTask(JNIEnv* env, jobject thiz) {
    pthread_mutex_lock(&task_mutex);
    task_is_completed = 0; // Reset state
    start_async_task(); // Kick off the async operation that triggers on_task_finished()
    
    // Wait until the callback signals completion
    while (!task_is_completed) {
        pthread_cond_wait(&task_cond, &task_mutex);
    }
    pthread_mutex_unlock(&task_mutex);
}

Option 3: Leverage Java's Synchronization Tools

If you have access to Java objects from JNI, using CountDownLatch is a clean way to align with Java's concurrency model:

JNIEXPORT void JNICALL Java_com_yourpackage_YourClass_waitWithLatch(JNIEnv* env, jobject thiz) {
    // Look up CountDownLatch class and constructor
    jclass latch_cls = (*env)->FindClass(env, "java/util/concurrent/CountDownLatch");
    jmethodID latch_ctor = (*env)->GetMethodID(env, latch_cls, "<init>", "(I)V");
    jobject latch = (*env)->NewObject(env, latch_cls, latch_ctor, 1); // Countdown from 1
    
    // Pass the latch to your async task; task calls countDown() when done
    start_async_task_with_latch(latch);
    
    // Block until latch reaches 0
    jmethodID await_method = (*env)->GetMethodID(env, latch_cls, "await", "()V");
    (*env)->CallVoidMethod(env, latch, await_method);
    
    // Clean up local references
    (*env)->DeleteLocalRef(env, latch);
    (*env)->DeleteLocalRef(env, latch_cls);
}
2. Implement Synchronous Logic for getChatList() in Telegram JNI Lib

TDLib's API is inherently async, so your recursive callback approach needs a sync wrapper to wait until all chats are loaded. Here's how to refactor it:

Step 1: Set Up Sync Primitives

First, define thread-safe variables to track chat list progress:

#include <pthread.h>
#include <td/telegram/Client.h>

// Sync primitives
pthread_mutex_t chat_list_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t chat_list_cond = PTHREAD_COND_INITIALIZER;
int all_chats_loaded = 0;
TdApi::Chats* full_chat_list = nullptr;

Step 2: Update TDLib Callback to Load All Chats

Modify your TDLib update handler to collect all chats and signal when done:

void handle_tdlib_update(TdApi::Object* update) {
    if (update->get_id() == TdApi::Chats::ID) {
        pthread_mutex_lock(&chat_list_mutex);
        TdApi::Chats* fetched_chats = static_cast<TdApi::Chats*>(update);
        
        // Initialize full chat list if first fetch
        if (!full_chat_list) {
            full_chat_list = new TdApi::Chats();
            full_chat_list->totalCount = fetched_chats->totalCount;
        }
        
        // Merge fetched chat IDs into the full list
        full_chat_list->chatIds.insert(
            full_chat_list->chatIds.end(),
            fetched_chats->chatIds.begin(),
            fetched_chats->chatIds.end()
        );
        
        // Check if we've loaded all chats
        if (full_chat_list->chatIds.size() >= full_chat_list->totalCount) {
            all_chats_loaded = 1;
            pthread_cond_signal(&chat_list_cond); // Notify waiting JNI method
        } else {
            // Fetch remaining chats (adjust limit as needed)
            auto next_get_chats = new TdApi::GetChats();
            next_get_chats->offsetOrder = fetched_chats->chatIds.back();
            next_get_chats->offsetChatId = 0;
            next_get_chats->limit = 100;
            td::Client::execute(next_get_chats);
        }
        pthread_mutex_unlock(&chat_list_mutex);
    }
    
    // Handle other updates (like errors) here to avoid hanging
    if (update->get_id() == TdApi::Error::ID) {
        pthread_mutex_lock(&chat_list_mutex);
        all_chats_loaded = 1; // Signal error to unblock waiting thread
        pthread_cond_signal(&chat_list_cond);
        pthread_mutex_unlock(&chat_list_mutex);
    }
    
    delete update; // Always clean up TDLib objects
}

Step 3: Implement Synchronous getChatList() JNI Method

Now create the JNI method that triggers the fetch and waits for completion:

JNIEXPORT jobjectArray JNICALL Java_com_yourpackage_TelegramClient_getChatList(JNIEnv* env, jobject thiz) {
    pthread_mutex_lock(&chat_list_mutex);
    // Reset state for new request
    all_chats_loaded = 0;
    if (full_chat_list) {
        delete full_chat_list;
        full_chat_list = nullptr;
    }
    pthread_mutex_unlock(&chat_list_mutex);
    
    // Send initial GetChats request
    auto initial_get_chats = new TdApi::GetChats();
    initial_get_chats->offsetOrder = 9223372036854775807LL; // Start with latest chats
    initial_get_chats->offsetChatId = 0;
    initial_get_chats->limit = 100;
    td::Client::execute(initial_get_chats);
    
    // Wait until all chats are loaded or error occurs
    pthread_mutex_lock(&chat_list_mutex);
    while (!all_chats_loaded) {
        pthread_cond_wait(&chat_list_cond, &chat_list_mutex);
    }
    
    // Convert chat IDs to Java long array
    jobjectArray chat_ids = nullptr;
    if (full_chat_list && !full_chat_list->chatIds.empty()) {
        chat_ids = (*env)->NewLongArray(env, full_chat_list->chatIds.size());
        (*env)->SetLongArrayRegion(
            env, chat_ids, 0,
            full_chat_list->chatIds.size(),
            full_chat_list->chatIds.data()
        );
    }
    
    // Clean up
    delete full_chat_list;
    full_chat_list = nullptr;
    all_chats_loaded = 0;
    pthread_mutex_unlock(&chat_list_mutex);
    
    return chat_ids;
}

Key Notes for Production

  • Error Handling: Add proper checks for TDLib errors (like network issues) to avoid infinite waits.
  • Thread Safety: Always guard shared variables with mutexes—TDLib's callbacks run in a separate thread.
  • Memory Management: Be diligent about deleting TDLib objects and JNI local references to prevent leaks.

内容的提问来源于stack exchange,提问作者Stanislav Zazhogin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:15:03