14 травня 2015 р.

Перші спроби багатопотокового програмування Qt5

Існує задача обробки зображень, по пікселям обробляється у циклі. 
Наприклад:
for (int i = 0; i < numPixels; i++, data += pixelSize) {
 if (output->colors == 3) {
  pixels[i * 4] = data[2 * colorSize];
  pixels[i * 4 + 1] = data[1 * colorSize];
  pixels[i * 4 + 2] = data[0];
 }
 else {
  pixels[i * 4] = data[0];
  pixels[i * 4 + 1] = data[0];
  pixels[i * 4 + 2] = data[0];
 }
}
З метою оптимізації розрахунку, спробую використати можливості багатопроцесорного комп'ютера.
Використовуючи фрейморк Qt 5.4.0. Створив новий клас IncTask. Вхідні дані до потоку можливо передати тільки під час ініціалізації класу. А надалі використовувати приватні змінні.
#include <QRunnable>
#include <QThreadPool>
 
class IncTask : public QRunnable {
public:
IncTask(int sstart, int scolorSize, int scolors, int spixelSize,
  int snumPixels, uchar *sdata, uchar *spixels) :
 start(sstart),
 colorSize(scolorSize),
 colors(scolors),
 pixelSize(spixelSize),
 numPixels(snumPixels),
 cdata(sdata),
 pixels(spixels)
{
}
 
virtual void run()
{
 qDebug() << "from thread start" << start << "end" << numPixels;
 uchar *data = cdata;
 data += (pixelSize*start);
 for (int i = start; i < numPixels; i++, data += pixelSize) {
 if (colors == 3) {
  pixels[i * 4] = data[2 * colorSize];
  pixels[i * 4 + 1] = data[1 * colorSize];
  pixels[i * 4 + 2] = data[0];
 }
 else {
  pixels[i * 4] = data[0];
  pixels[i * 4 + 1] = data[0];
  pixels[i * 4 + 2] = data[0];
 }
 }
}
virtual bool autoDelete(){
 return true;
}
 
private:
 int start, colorSize, colors, pixelSize, numPixels;
 uchar *cdata;
 uchar *pixels;
};

Надалі у тілі програми, створюємо екземпляри класу IncTask  у кількості рівної максимальної кількості потоків у системі. У моєму випадку це 8.
qDebug() << "converting LIBRAW_IMAGE_RAW";
int numPixels = output->width * output->height;
int colorSize = output->bits / 8;
int pixelSize = output->colors * colorSize;
pixels = new uchar[numPixels * 4];
uchar *data = output->data;
timer.restart();
 
//split calculation to threads
int maximumThreadCount = QThreadPool::globalInstance()->maxThreadCount();
qDebug() << "maximumThreadCount" << maximumThreadCount;
int threadCount = maximumThreadCount; int perThread = numPixels / threadCount;
for (int threadId = 0; threadId<threadCount; threadId++){
  int start = perThread*threadId;
  int end = (perThread*(threadId + 1));
  QThreadPool::globalInstance()->start(new IncTask(start, colorSize, output->colors, pixelSize, end, data, pixels));
}
QThreadPool::globalInstance()->waitForDone();
qDebug() << "converting loop elapsed" << timer.elapsed() / 1000. << "sec.";

Таким чином на потоки розбито частини обробки всього зображення на потоки.
converting LIBRAW_IMAGE_RAW 
maximumThreadCount 8 
from thread start 0 end 2263744 
from thread start 2263744 end 4527488 
from thread start 4527488 end 6791232 
from thread start 6791232 end 9054976 
from thread start 9054976 end 11318720 
from thread start 11318720 end 13582464 
from thread start 13582464 end 15846208 
from thread start 15846208 end 18109952 
converting loop elapsed 0.034 sec.

Дяка: QThreadPool - BlackBerry Native, code of QtRaw, Qt Multi Threaded Programming | Ynon Perek 

Немає коментарів:


Коли забув ти рідну мову, біднієш духом ти щодня...
When you forgot your native language you would become a poor at spirit every day ...

Д.Білоус / D.Bilous
Рабів до раю не пускають. Будь вільним!

ipv6 ready