Android: 线程同步和处理器同步

4
我是一名有用的助手,可以为您翻译文本。
我遇到了一些关于我的应用程序的问题。我非常新于Android开发,所以希望这只是一个简单的错误。 我正在尝试编写一个应用程序,通过Wifi获取一些原始数据(第一个线程),进行一些计算(第二个线程),将计算出的数据创建为位图(第三个线程)并更新显示(处理程序)。 某些参数由SeekBar调整。一切都运行良好。但有时当我更改SeekBar值时,图片不再更新。线程和处理程序仍在运行,所以我没有得到错误。
以下是一些代码:
MainActivity:
public class MainActivity extends Activity implements OnClickListener {
    private Handler outputHandler = new Handler();
    private SeekBar  seekBarBrightness,
    seekBarContrast,
    seekBarGamma;

    public static volatile double gamma = 1;
    public static volatile double brightness = 500;
    public static volatile double contrast = 500; 
    public static volatile double min = 0;
    public static volatile double max = 0;

    public static volatile boolean isRunning = false;

    public static volatile int r = 0;
    public static volatile int g = 0;
    public static volatile int b = 0;
    public static volatile int width = 400;
    public static volatile int height = 250;

    public volatile double inputExchangeFrame[][ ]= new double[400][250], outputExchangeFrame[][]= new double[400][250];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        seekBarBrightness = (SeekBar) findViewById(R.id.seekBarBrightness); 
        seekBarContrast = (SeekBar) findViewById(R.id.seekBarContrast);
        SeekBarGamma = (SeekBar) findViewById(R.id.seekBarGamma);

        newImage = Bitmap.createBitmap(width, height, BitmapConfig.ARGB_8888);              
        picture.setImageBitmap(newImage);


    }    

    @Override   
    public void onClick(View v) { 
        if(v==toggleButtonStartStop){
            if(toggleButtonStartStop.isChecked()==true){ 
                isRunning=true; 
                getFrame();
                calculateFrame();
                showFrame();
            }
            else{ 
                isRunning = false;
            }
        }
    }            
}

在MainActivity中还声明了其他方法: getFrame():

private synchronized void getFrame(){
     inputThread = new Runnable(){
          public void run(){
               while(isRunning == true){

                   //inputFrame fron WIFI

                    inputExchangeFrameLock.lock();
                    //synchronized(inputExchangeFrame){
                         for(int x_1=0 ; x_1<width ; x_1++){
                              for(int y_1=0 ; y_1<height ; y_1++){
                                   inputExchangeFrame[x_1][y_1]=inputFrame[x_1][y_1];
                              }
                         }
                    //}
                   inputExchangeFrameLock.unlock();

                   try {                        
                        Thread.sleep(120);
                   } 
                   catch (InterruptedException e) {
                        e.printStackTrace();
                   }
              }
         }
     };new Thread(inputThread).start();
};

计算框架:

private synchronized void calculateFrame(){
     calculationThread = new Runnable(){
          public void run(){
               while(isRunning == true){    
               //get Data from InputThread to applicate several Filter
               inputExchangeFrameLock.lock();
               //synchronized(inputExchangeFrame){
                    for(int x_2=0 ; x_2<width ; x_2++){
                         for(int y_2=0 ; y_2<height ; y_2++){
                              calculationFrame[x_2][y_2]=inputExchangeFrame[x_2][y_2];
                         }
                    }
               //}
               inputExchangeFrameLock.unlock();

                 //Do some calculations on calculationFrame  

               outputExchangeFrameLock.lock();
               //synchronized(outputExchangeFrame){ 
                    for(int x_3=0 ; x_3<width ; x_3++){
                         for(int y_3=0 ; y_3<height ; y_3++){
                              outputExchangeFrame[x_3][y_3] = calculationFrame[x_3][y_3];
                         }
                    }
               //}
               outputExchangeFrameLock.unlock();
               }
          }
     }; new Thread(calculationThread).start();
};

showFrame():

private synchronized void showFrame(){
     outputThread = new Runnable(){
          public void 
               while(isRunning == true){
                    contrast =  seekBarContrast.getProgress() +1;
                    brightness = seekBarBrightness.getProgress() + 1;
                    gamma = seekBarGamma.getProgress() + 1;

                    outputExchangeFrameLock.lock();
                    //synchronized(outputExchangeFrame){
                    for(int x_4=0 ; x_4<width ; x_4++){
                         for(int y_4=0 ; y_4<height ; y_4++){
                              outputFrame[x_4][y_4] = outputExchangeFrame[x_4][y_4];
                          }
                     }  
                     //}
                     outputExchangeFrameLock.unlock();

                     for (int x_14=0 ; x_14<width ; x_14++){
                          for(int y_14=0; y_14<height; y_14++){

                             //Calculation of r,g,b  using gamma, brightness and contrast
                          }
                          synchronized(newImage){
                               newImage.setPixel(x_14, y_14, Color.rgb(r,g,b));
                          }
                     }

                     outputHandler.removeCallbacks(pictureUpdate);
                     outputHandler.post(pictureUpdate);

                     try {
                          Thread.sleep(50);
                     } 
                     catch (InterruptedException e) {
                          e.printStackTrace();
                     }
                }
           }
     }; new Thread(outputThread).start();   
};

您好!以下是您需要翻译的内容,涉及到IT技术,我会尽力使其更加易懂。

还有处理程序:

private Runnable pictureUpdate = new Runnable(){
public void run(){ synchronized(newImage){ picture.setImageBitmap(newImage);
} }
};

我知道这是很多文本。但是我真的不知道从哪里开始搜索以及我可以做什么来找到错误。

任何建议都将是极好的!

谢谢

迈克尔

1个回答

3
您正在实现一些线程,而您尝试执行的操作顺序并不确定。
例如,可能在执行“showFrame.Runable()。run()”之前先执行了getFrame.Runable()。run()。
关键字“synchronize”无法帮助,因为当在单独的线程中执行任务时,同步函数调用将返回,并且锁将被释放。
使用“locks”也无法确保正确的顺序。
我的建议是使用AsyncTask,http://developer.android.com/reference/android/os/AsyncTask.html。您可以这样做:
private class ProcessFrameTask extends AsyncTask {

 protected void doInBackground(Object... objs) {
     getFrame(); // Copy the frame
     calculateFrame(); // Do your magic
 }

 protected void onPostExecute(Long result) {
     showFrame(); // Post the result back to main thread
 }

不使用多线程和协作,只有一个工作线程完成所有工作,并将结果返回到主线程。


感谢您的快速回复。我已经考虑了AsynkTask解决方案。但问题是计算部分非常耗费CPU资源,而Wifi数据传输速率非常慢。我的概念是始终从Wifi中获取新的原始数据,这样我就可以在计算线程中拥有实际数据。只有一个工作线程会使这个过程变慢,或者我错了吗?在Asynktask中使用while(true)是可能的吗,还是应该在onPostExecute中执行“new ProcessFrameTask.execute();”? - user2282554
  1. 多线程通常不会增加吞吐量。如果您有多个核心,可以进行一些测试来确定是否会增加吞吐量。
  2. 如果瓶颈是 WiFi,并且您希望用户在数据到达时看到数据,请使用 java.util.concurrent 进行多线程处理,而不是自己实现。一个简单的方法是让一个线程等待数据,并在有足够的数据时将其发布到另一个线程进行处理。
- dongshengcn
现在我尝试了你的解决方案。不幸的是,问题依旧存在。一切都正常工作,但有时在我更改任何seekBarValue后,图片不再更新。我尝试了一些USB调试,现在我得到了这个错误:"OpenGLRenderer无法从位图生成纹理"。可能我的错误是图片像素比ImageView少吗?我希望Android可以自动插值。但似乎我必须自己做这个。还是有其他问题吗?谢谢。 - user2282554
我不确定问题出在哪里。提供一个堆栈跟踪可能会很好。另外,也请尝试通过确保您的代码在没有任何线程代码的情况下工作来分离关注点。 - dongshengcn
我想我解决了这个问题。我不确定,但我认为应用程序想要创建位图时使用了一个标记为GC销毁的对象。因此,该对象仍然存在,但无法用于更新显示。这就是为什么没有错误消息的原因。现在,我每次循环都创建一个新的位图对象,计算位图并且似乎它可以工作。我将采用您推荐的AsyncTask解决方案。同步起来更容易。非常感谢您的帮助! - user2282554
有线问题。您可能希望单独发布另一个问题。您可能希望在内存中拥有两个图像进行交换,而不是每次创建新图像。无论如何,很高兴看到您已经准备就绪。 - dongshengcn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接