1

我正在编写在其他线程上处理 Android OpenGL 的程序。但如果出现此代码,它会冻结。例如,如果它是同一个线程,它直接处理一个方法而不调用 task.get()。这种方式存在吗?

public void onSurfaceCreated(GL10 arg0, EGLConfig arg1)
{
    Thread t = new Thread(new Runnable(){
        @Override
        public void run()
        {
            FutureTask<Object> task = new FutureTask<Object>(new Callable<Object>() {
                @Override
                public Object call() {
                    return null;
                }
            });
            gv.queueEvent(task);
            try{
                task.get();
            }catch(Exception e){

            }
            Log.i("MainActivity", "Done");    // <- Work
        }
    });
    t.start();

    FutureTask<Object> task = new FutureTask<Object>(new Callable<Object>() {
        @Override
        public Object call() {
            return null;
        }
    });
    gv.queueEvent(task);
    try{ task.get(); }catch(Exception e){}    // <- Freeze
    Log.i("MainActivity", "Done");
4

1 回答 1

1

如果我正确解释了您的问题,那么您希望在 OpenGL 线程中运行一些代码,而不使用或其他异步解决方案。FutureTaskRunnable

首先,这段代码(及其任何数据)是否依赖于其他线程?是否需要与其他代码/数据同步?如果是,那么您应该queueEvent()从不同的线程中使用。由于您想完全留在 OpenGL 线程中,我假设您要执行的代码与其他(非 GL)线程没有任何关系。

此外,永远不要FutureTask.get()从与应该执行代码的线程相同的线程中调用FutureTask——如果你的线程正在等待自己,谁来执行这项工作?如果你想从另一个线程向 GL 线程发送代码,不要使用FutureTask; 只需Runnable对它使用简单的(作为 的参数queueEvent())。

回到主要问题:要在不使用 GL 线程的情况下运行某些queueEvent()内容,您应该决定您希望如何准确地执行该工作,即应该在何时(何地)准确地调用它。你想在每次调用时onDrawFrame()都调用它吗?还是每次onSurfaceChanged()或被onSurfaceCreated()调用?

由于您使用queueEvent()了 ,我假设您希望您的代码在下一个即将到来的onDrawFrame()调用之前运行。在Android GL线程内部,调用顺序如下:

  1. Android 处理所有排队的事件(我简化了一点,但要点是好的)
  2. 如果需要,Android 调用onSurfaceCreated()
  3. 如果需要,Android 调用onSurfaceChanged()
  4. 安卓通话onDrawFrame()

因此,简单地说,您添加的代码queueEvent()将在下一个渲染周期 ( onDrawFrame()) 之前执行。如果要在 GL 线程上运行这段代码onDrawFrame(),可以将其添加到 的开头onDrawFrame(),例如:

@Override
public void onDrawFrame(GL10 gl) {
    if (mDoJob) {
        mDoJob = false;

        // perform code
    }

    ...
}

这里,mDoJob是一个volatile变量。您可以将其设置为true来自另一个线程。但是,请注意,这假设您不需要与使用该mDoJob信号的其他线程进行任何额外的同步,即,将在mDoJob条件块中运行的所有代码都可以正常运行,而无需与其他任何东西进一步同步。

基本上,我上面介绍的只是一个简化的(非同步的)替换解决方案queueEvent(),它假设您不需要与其他线程同步(包括最新的变量)。

如果您不需要任何信号(与其他线程的任何依赖关系),并且 的值mDoJob可以在 OpenGL 线程内部(内部onDrawFrame()onSurfaceCreated()onSurfaceChanged())决定,则mDoJob不需要是 volatile。在这种情况下,您将停留在 OpenGL 线程中,因此不需要异步(因此是同步的)解决方案。

总而言之,具体来说,如果您想决定onSurfaceCreated()代码是否应该在 中运行onDrawFrame(),只需使用您在 中设置的(非易失性)布尔变量,onSurfaceCreated()然后将其签入onDrawFrame()(如我上面的代码示例所示)。

于 2012-12-20T09:31:35.137 回答