【问题标题】:How to solve the problem of NDK library calls freezing UI thread如何解决NDK库调用冻结UI线程的问题
【发布时间】:2010-11-02 08:48:26
【问题描述】:

我有一个通过 NDK 访问的 C 库。有些操作很耗时,因此 UI 线程会冻结它们。我现在的常见做法是像这样使用 Runnable:

myFixedThreadPool.execute(new Runnable() 
{
  public void run() 
  {
    NativeClass.callToNDKLibrary();
  };
});

或类似的线程:

Thread t = new Thread() 
{
  public void run() 
  {
    NativeClass.callToNDKLibrary();
  }
};
t.start();  

但问题是 C 库不是线程安全的:当我这样包装它时它开始崩溃。所以问题是如何从 UI 线程中分离仍然强制 NDK 调用一次运行一个。同步的一些技巧可能会有所帮助吗?我还想提一下,这个库是我的应用程序的核心底层,而不仅仅是一个辅助函数。所以它几乎是从我的代码的每个部分调用的。并且只有少数函数会消耗时间,大多数可以快速将它们保留在主线程中。

【问题讨论】:

    标签: android multithreading android-ndk


    【解决方案1】:

    最终解决方案如下:

    1. 将所有 JNI 本机方法定义为同步。这将防止 C 库崩溃,但仍会冻结 UI。
    2. 定义单线程执行器:

      ExecutorService mExecutorThread = Executors.newSingleThreadExecutor();

    3. 将所有耗时的操作封装在该线程中:

      mExecutorThread.execute(new Runnable() { 公共无效运行() { NativeClass.callToNDKLibrary(); } });

    我必须做的最后一件事是稍微重新设计我的代码,以确保不会从 onDraw() 调用任何本机方法。我将本地方法的结果缓存在事件处理程序中,并在 onDraw() 中使用缓存的值。

    【讨论】:

      【解决方案2】:

      但问题是 C 库不是线程安全的:当我这样包装它时它开始崩溃。

      然后对库上的所有操作使用单个专用后台线程。例如,使用 IntentService 访问库,活动调用 startService() 将命令发送到 IntentService

      或者:

      1. 为您定义的一些Job 类/接口创建一个LinkedBlockingQueue<Job>
      2. 有一个单线程监视器该队列
      3. 将作业发送到该队列以访问您的库
      4. 一旦您不再需要队列和线程,就向队列发送一个特殊的“终止作业”以导致监视器队列循环退出,从而导致后台线程终止

      或者,花时间在 C 级别使库线程安全。使 C 代码成为线程安全的话题已经讨论了大约 20 年,因此可能有一些您可以使用的技巧来自所有这些经验。

      【讨论】:

      • 谢谢,它给了我从哪里开始思考的线索。
      【解决方案3】:

      您可以使用Looper 创建消息循环。然后通过 Handler 传递您的 NDK 调用,每个调用都会依次运行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-08-21
        • 2021-12-21
        • 1970-01-01
        • 1970-01-01
        • 2011-06-22
        • 1970-01-01
        • 2021-05-13
        相关资源
        最近更新 更多