2016-08-27 6 views
0

Во время работы над Android-приложением я наткнулся на что-то и хотел получить ваше мнение/помощь по этому вопросу.Android - Threads, Runnable и одновременный доступ к данным

Итак, в основном, я создаю несколько Runnable s, которые запускаются в разных потоках. Все это Runnable s вызывает метод ApplyContrast(...) из класса SomeClass, который запускает эти Runnable s (более или менее одновременно). Этот метод ApplyContrast(...) осуществляет доступ и изменяет int[] этого же класса SomeClass.

Так что мне было интересно, если это было/может быть проблемой? Я спрашиваю об этом, потому что я не получаю ожидаемый результат, когда я запускаю его более чем на один поток.

P.S: Даже если есть одновременный доступ к int[] нити не могут получить доступ к той же части массива (или не должны делать это: P)

Любая помощь приветствуется. Если вам нужна дополнительная информация, просто спросите.

public class SomeClass extends SomeOtherClass { 

    // The number of threads that will be used to do the data processing 
    private static int mNumberOfThreadsToCreate = 10; 

    private int mPixelArrayLength; 

    private int mRunningThreadCount; 

    public SomeClass(AnotherClass callback, int[] pixels, int length) { 
     super(callback, pixels); 

     mPixelArrayLength = length; 
     mRunningThreadCount = mNumberOfThreadsToCreate; 
    } 

    public void run() { 
     new Thread(new Runnable() { 
      public void run() {  
       final int lenByChunk = mPixelArrayLength/mNumberOfThreadsToCreate; 
       for (int i = 0; i < mNumberOfThreadsToCreate; ++i) { 
        int len = lenByChunk; 
        if (i == (mNumberOfThreadsToCreate - 1)) 
         len += (mPixelArrayLength - mNumberOfThreadsToCreate * lenByChunk); 
        applyToChunk(mPixels, i * lenByChunk, len, 128); 
       } 
      } 
     }).start(); 
    } 

    private void applyToChunk(final int[] pixels, final int offset, final int len, final int contrastLevel) { 
     new Thread(new Runnable() { 
      public void run() { 
       applyContrast(pixels, offset, len, contrastLevel);  
       --mRunningThreadCount;  
       onFinish(); 
      } 
     }).start(); 
    } 

    //set value in range 0 - 255 
    private int keepInRange(int colorValue) { 
     if (colorValue < 0) 
      colorValue = 0; 
     else if (colorValue > 255) 
      colorValue = 255; 

     return colorValue; 
    } 

    /** 
    * contrastLevel should be in <-128, 128> range 
    */ 
    private void applyContrast(int[] pixels, int offset, int pixelsLen, int contrastLevel) { 
     double correctionFactor = 259.047619047619; 
     double factor = (correctionFactor * (contrastLevel + 255))/(255 * (correctionFactor - contrastLevel)); 

     for(int i = offset; i < pixelsLen; ++i) { 

      int red = keepInRange((int)(factor * (Color.red(pixels[i]) - 128) + 128)); 
      int green = keepInRange((int)(factor * (Color.green(pixels[i]) - 128) + 128)); 
      int blue = keepInRange((int)(factor * (Color.blue(pixels[i]) - 128) + 128)); 
      int alpha = Color.alpha(pixels[i]); 
      pixels[i] = Color.argb(alpha, blue, green, red);//invert sequence here. 
     } 
    } 

    private void onFinish() { 
     // Shouldn't be < 0 or there is a really serious problem ... 
     if (mRunningThreadCount <= 0 && super.mCallback != null) { 
      super.mCallback.onFinish(super.mPixels); 
     } 
    } 
} 

UPDATE # 1:

Чтобы добавить немного больше информации о том, что (неправильно) результат:

Как я уже говорил выше, я не получаю ожидаемый результат всегда, когда Я обрабатываю данные в нескольких потоках. Когда обработка данных выполняется в нескольких потоках только данные, обработанные в первом потоке (который был запущен), являются правильными.

Вот некоторые фотографии, чтобы показать исходное изображение, ожидаемый результат и фактическое конечное изображение я получаю, когда многопоточность:

(Не против синих частей на верхнем и на нижней части картинки)

Исходное изображение: enter image description here

Ожидаемое результирующее изображение: enter image description here

Фактическое результирующее изображение: enter image description here

Вы можете видеть, что в последнем изображении мы имеем «2 части». Первая часть (вверху) - первая, обработанная 1-й нитью (это сделано правильно), а вторая (внизу) обрабатывается всеми оставшимися нитями (это не так).

ответ

0

Я думаю, что все в порядке.

Массив pixels (возможно, псевдоним, как mPixels) доступен из нескольких потоков. Это сделает его неправильным.

Похоже, что вы блокируете доступ к массиву, чтобы каждый поток получал доступ только к его собственному фрагменту. Пока несколько потоков никогда не обращаются к одному и тому же месту в массиве, код верен.

Я должен сказать, что это дико запутанно. Я бы сказал, что переменная len неверно. Конечно, правильность параллелизма действительно трудно определить. Я считаю, что его можно было бы написать более четко и что, с чем-то таким склонным к ошибкам, было бы полезно это сделать.

+0

Верно, что переменная 'len' неверна. Я проверял ее содержимое, и там нет ничего плохого. Я обновил сообщение. Пожалуйста, посмотрите, есть ли у вас время. – Moucheg