Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: AlphaGh0St от Ноября 21, 2011, 13:56



Название: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 21, 2011, 13:56
Всем привет!
Мне нужно написать программку, которая в многопоточном режиме осветляет пиксели на картинке.
У меня есть документация по работе с потоками в Qt, но, что касается самого осветления пикселей...даже не представляю, с чего начать.

Подскажите, кто знает, как это делается.
Благодарю.


Название: Re: Многопоточное осветление пикселей
Отправлено: LisandreL от Ноября 21, 2011, 14:08
что касается самого осветления пикселей...даже не представляю, с чего начать.
Что вы подразумеваете под осветлением? Увеличение I в HSI?


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 21, 2011, 15:10
У меня нет опыта а в обработке изображений. Просто нужно написать небольшую демонстрационную программку.
Программа, демонстрирующая преимущества многопоточности в Qt. В качестве работы для потоков, решил сделать осветление пикселей.

>> Увеличение I в HSI?
Не совсем понимаю вопрос.

Ну суть какова: мы выбрали картинку, загрузили её в программу (QPixmap или QImage, что лучше?)).
Далее в многопоточном режиме осветляем картинку пиксель за пикселем.
Осветление - оно и есть осветление, сделать картинку чуть ярче, что-ли.


Название: Re: Многопоточное осветление пикселей
Отправлено: LisandreL от Ноября 21, 2011, 15:39
>> Увеличение I в HSI?
Не совсем понимаю вопрос.
http://ru.wikipedia.org/wiki/HSI


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Ноября 21, 2011, 17:31
Так вполне устроит HSV модель. Берете пиксель (RGB). перегоняете его в HSV (QColor::getHsv), увеличиваете V и записываете назад в RGB (QColor::setHsv). Каждой нитке даете определенное число строк для обработке (проще всего)


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 23, 2011, 18:51
Спасибо, помогло!
Продолжу работать над программой...


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 24, 2011, 12:25
Такой вопрос:
Определил класс для многопоточного осветления пикселей
Код:
class ImageThread : public QThread { ... };

В главном классе создаю несколько потоков:
Код:
    for(int i = 0; i < threadsLimit; i++)
        imgThread[i].run();

При выводе отладочной информации, qDebug показывает, что у всех потоков один и тот же идентификатор.
Например:
При threadsLimit = 1, qDebug показывает:
Код:
ID: 0xc10 

При threadsLimit = 2, qDebug показывает:
Код:
ID: 0xc10 
ID: 0xc10

При threadsLimit = 3, qDebug показывает:
Код:
ID: 0xc10 
ID: 0xc10
ID: 0xc10

Может я где-то ошибся и, действительно, создаётся только один поток?


Название: Re: Многопоточное осветление пикселей
Отправлено: BRE от Ноября 24, 2011, 12:31
Потоки запускаются методом start!!!


Название: Re: Многопоточное осветление пикселей
Отправлено: Bepec от Ноября 24, 2011, 13:23
run - выполнение функции run;
start - запуск потока, который выполняет функцию run;


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 24, 2011, 15:14
Ок, с этим ясно.
Возникла другая проблема.

При запуске программы в одном потоке, проблем нет. Но если запускать её хотя бы в двух потоках, то программа вылетает.
Просто завершается с кодом "-1073741819" или ему подобным.

Тут запускаем потоки из главного класса:
Код:
    for(int i = 0; i < threadsLimit; i++)
        imgThread[i].start();

А вот метод run(). Указатель на картинку (QImage) получаем из главного класса, по этому блокируем её мьютексом.
Код:
void ImageThread::run(){
    QSize countOfPixels = t_image->size(); // кол-во пикселей
    QRgb rgb;
    QColor color;
    int h = 0, s = 0, v = 0;

    time.start(); // замеряем время выполнения

    // проходим по всем пикселям
    for(int i = 0; i < countOfPixels.width(); i++){
        for(int j = 0; j < countOfPixels.height(); j++){

            // берём текущий пиксель
            t_mutexRead.lock();
                rgb = t_image->pixel(i, j);
            t_mutexRead.unlock();

            // увеличиваем яркость
            color.setRgb(rgb);
            color.getHsv(&h, &s, &v);
            v += t_brightnessValue; // значение, на которое надо увеличить яркость
            color.setHsv(h, s, v);

            // сохраняем изменённый пиксель
            t_mutexWrite.lock();
                t_image->setPixel(i, j, color.rgb());
            t_mutexWrite.unlock();
            }
        }

    // сообщаем главному классу, что работа завершена и время выполнения.
    emit workDone("MS:" + QString("%1").arg(time.elapsed()));
}

Из отладочной информации тоже не стало ясно, почему программа вылетает. Завершение происходит ни на одном и том же месте, а в разных местах: то на записи обработанного пикселя, то на увеличении яркости.

Ещё одна странность. Из отладки видно, что при запуске программы в двух потоках, получает управление только один поток. Этот поток входит в цикл и начинает работать, но другого потока нет. Этот один поток продолжает работать, а потом программа вылетает.

Вот отладочная информация:
Код:
Видим, что поток с ID 0xcd8 вошёл в метод, вошёл в первый цикл и во второй.
THREAD BEGIN  | ID:  0xcd8
ENTER IN 1ST LOOP  | ID:  0xcd8
ENTER IN 2ND LOOP  | ID:  0xcd8


Далее начинается выполнение:
BLOCK MUTEX AND READ  | ID:  0xcd8
CHANGE DATA  | ID:  0xcd8
BLOCK MUTEX AND WRITE  | ID:  0xcd8
И так много-много раз...
...

И в конце:
BLOCK MUTEX AND READ  | ID:  0xcd8
CHANGE DATA  | ID:  0xcd8
И программа вылетела

Не могу понять, в чём проблема.
Подскажите, где я ошибся?


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Ноября 24, 2011, 16:06
Писал прямо здесь, ошибки возможны
Код
C++ (Qt)
// члены класса ImageThread
// mSelfIndex - индекс нитки
// mTeamCount - число ниток-обработчиков
void ImageThread::run()
{
   QColor color;
   int h, s, v;
 
   time.start(); // замеряем время выполнения
 
   int numRow = t_image.height() / mTeamCount;  // число строк для обработки
   int begRow = numRow * mSelfIndex;                // первая стока
   int endRow = (mSelfIndex == mTeamCount - 1) ? t_image.height() : (begRow + numRow); // предел
 
   for(int row = begRow; row < endRow; ++row) {
       unsigned int * data = (unsigned int *) t_image.scanLine(row);
       for(int col = 0; col < t_image.width(); ++col){
           unsigned int & pix = data[col];
           color.setRgb(qRed(pix), qGreen(pix), qBlue(pix));
           color.getHsv(&h, &s, &v);
           v += t_brightnessValue; // значение, на которое надо увеличить яркость
           v = qMin(v, 255);
           color.setHsv(h, s, v);
 
           // сохраняем изменённый пиксель
           pix = qRgba(color.red(), color.green(), color.blue(), qAlpha(pix));
        }
    }
 
   // сообщаем главному классу, что работа завершена и время выполнения.
   emit workDone("MS:" + QString("%1").arg(time.elapsed()));
}


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 24, 2011, 19:29
В циклах всё понятно, код замечательный у Вас ))

Не понятно только вот здесь:
Код:
// mSelfIndex - индекс нитки
// mTeamCount - число ниток-обработчиков

int numRow = t_image.height() / mTeamCount;  // число строк для обработки
int begRow = numRow * mSelfIndex;                // первая стока
int endRow = (mSelfIndex == mTeamCount - 1) ? t_image.height() : (begRow + numRow); // предел

mTeamCount - кол-во созданных потоков, полагаю?
А вот mSelfIndex? Индекс... в смысле идентификатор потока? Или его порядковый номер?

Вот тут что-то не совсем понял...


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Ноября 24, 2011, 19:57
А вот mSelfIndex? Индекс... в смысле идентификатор потока? Или его порядковый номер?

Вот тут что-то не совсем понял...
Порядковый - нитке нужно знать какие строки имеджа она будет обрабатывать. Просто передавайте в конструктор и еще: лучше сделать контейнер указателей (а не самих ImageThread), напр

Код
C++ (Qt)
ImageThread::ImageThread( int iIndex, int iCount ) :
 mSelfIndex(iIndex),
 mTeamCount(iCount)
{
...
}
 
// создаем все нитки
QVector <ImageThread *> theThread;
for (int i = 0; i < numThreads; ++i)
theThread.push_back(new ImageThread(i, numThreads));
 
// удаляем (после того как они отработали)
for (int i = 0; i < numThreads; ++i)   // ну или пресловутое qDeleteAll
delete theThread[i];
 
theThread.clear();
 


Название: Re: Многопоточное осветление пикселей
Отправлено: Sahab от Ноября 24, 2011, 21:42
OpenMP (http://en.wikipedia.org/wiki/OpenMP#C.2B.2B)


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Ноября 24, 2011, 22:14
OpenMP (http://en.wikipedia.org/wiki/OpenMP#C.2B.2B)
В данной задаче OpenMP ни к селу ни к городу. Ну разве что есть желание "пособирать"  :)


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 24, 2011, 22:56
Идея с контейнерами хороша. Но видите ли, задача данной программы: продемонстрировать преимущества многопоточности.
Программа рассчитана на слабую аудиторию, которая и в программировании-то не особо сильна, а Qt и в глаза не видела.

По этому хотелось бы сделать код на столько простым, насколько это вообще возможно.

Igors, спасибо за помощь! Я учту Ваши советы и продолжу работать над программой, однако, считаю, что контейнеры включать не стоит, т.к. из аудитории с STL врятли кто знаком.

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


Название: Re: Многопоточное осветление пикселей
Отправлено: Sahab от Ноября 24, 2011, 23:06
OpenMP (http://en.wikipedia.org/wiki/OpenMP#C.2B.2B)
В данной задаче OpenMP ни к селу ни к городу. Ну разве что есть желание "пособирать"  :)
ну смотря как на это смотреть...
учитывая
Цитировать
Программа, демонстрирующая преимущества многопоточности в Qt.
- то не подойдет.
если осветление пикселей в отдельном потоке - тоже.
если
Цитировать
Многопоточное осветление пикселей
то вполне подойдет.
хотя все это оффтоп


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 24, 2011, 23:44
Igors, Я изменил метод run() в соответствии с Вашими рекомендациями, но проблема осталась.

Пытаясь локализовать ошибку, я выводил отладочную информацию в каждом потоке, она состоит из сообщения о том, что поток с определённым ID начал работу, общее кол-во потоков, номер выполняемого потока, и сообщение о том, что поток завершился.

Вот отладочная информация при 1-м потоке:
Код:
thread begin # 0xf60 
team count   : 1
self index   : 0
thread done # 0xf60

При 2-х потоках:
Код:
thread begin # 0xc2c 
thread begin # 0xa14
team count   : 2
team count   : 2
self index   : 0
 
self index   : 1
 
thread done # 0xc2c

При 3-х потоках:
Код:
thread begin # 0x208 
thread begin # 0xe18
team count   : 3
thread begin # 0xf84
team count   : 3
self index   : 0
 
team count   : 3
self index   : 1
 
self index   : 2
 
thread done # 0x208

При 4-х потоках:
Код:
thread begin # 0x5fc 
thread begin # 0x8d0
team count   : 4
team count   : 4
thread begin # 0x9cc
self index   : 0
 
self index   : 1
 
thread begin # 0x4f8
team count   : 4
team count   : 4
self index   : 2
 
self index   : 3
 
thread done # 0x5fc

Завершается первый созданный поток и завершается вся программа.
Тут явно что-то не так... Но я никак не могу понять, что именно...


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Ноября 25, 2011, 10:43
Примерный код главной нитки
Код
C++ (Qt)
#define NUM_THREAD  4     // просто чтобы попроще
 
// здесь загружаем исходный t_image
 
// объявляем массив ниток
ImageThread theThread[NUM_THREAD];
 
// стартуем массив ниток
for (int i = 0; i < NUM_THREAD; ++i) {
theThread[i].mSelfIndex = i;              
theThread[i].mTeamCount = NUM_THREAD;
theThread[i].start();
}
 
// ждем пока все сделано
for (int i = 0; i < NUM_THREAD; ++i)
theThread[i].wait();
 
// здесь выводим "осветленный" t_image
 
Минус "просто массива" в том что нельзя передать параметры в конструктор каждого элемента, ну это можно перетерпеть


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 27, 2011, 12:28
Фуууух, наконец-то нашёл, в чём проблема.
Первый поток работает с указателем t_image, который указывает на QImage, содержащий картинку.
Когда начинает работать второй поток, указатель t_image почему-то содержит уже другой адрес, а потому программа и вылетала.

Сделал указатель t_image статическим, проблема решилась.

Igors, большое спасибо за помощь!


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 28, 2011, 19:20
Прям какое-то колдовство!
Работала программа, всё замечательно, и тут СНОВА та же проблема.

При запуске программы в нескольких потоках, она вылетает.
Отладчик показал, что программа вылетает из-за ошибки сегментации (SIGSEGV).
И вылетает на этой строке:
Код:
color.setRgb(qRed(pix), qGreen(pix), qBlue(pix));

Но гораздо чаще, вот на этой:
Код:
pix = qRgba(color.red(), color.green(), color.blue(), qAlpha(pix));

Сколько уже с ней провозился, никак не могу понять, в чём тут дело...
Если кто знает, подскажите, пожалуйста.

Ниже привожу код:
Код:
void ImageThread::run()
{
    QColor color;
    int h = 0, s = 0, v = 0;

    time.start(); // замеряем время выполнения

    int numRow = t_image->height() / t_TeamCount;  // число строк для обработки
    int beginRow = numRow * t_SelfIndex; // первая стока
    int endRow = (t_SelfIndex == t_TeamCount - 1) ? t_image->height() : (beginRow + numRow); // предел

    for(int row = beginRow; row < endRow; ++row){
        t_mutexRead.lock();
            unsigned int *data = (unsigned int *) t_image->scanLine(row);
        t_mutexRead.unlock();

        for(int column = 0; column < t_image->width(); ++column){
            t_mutexRead.lock();
                unsigned int &pix = data[column];
            t_mutexRead.unlock();

            color.setRgb(qRed(pix), qGreen(pix), qBlue(pix));
            color.getHsv(&h, &s, &v);
            v += t_brightnessValue; // значение, на которое надо увеличить яркость
            v = qMin(v, 255);
            color.setHsv(h, s, v);

            // сохраняем изменённый пиксель
            t_mutexWrite.lock();
                pix = qRgba(color.red(), color.green(), color.blue(), qAlpha(pix));
            t_mutexWrite.unlock();
         }
     }

    // сообщаем главному классу, что работа завершена и время выполнения.
    emit workDone("Ms: " + QString("%1").arg(time.elapsed()));
}

Запускаем потоки:
Код:
    // кол-во потоков
    int threadsLimit = ui->threadsSpinBox->text().toInt();

    // устанавливаем значения для потоков (это всё статические данные)
    imgThread[0].setBrightnessValue(ui->valueSpinBox->text().toInt()); // уровень яркости
    imgThread[0].setImagePointer(&image); // указатель на картинку
    imgThread[0].setTeamCount(threadsLimit); // всего потоков

    // запускаем потоки
    for(int i = 0; i < threadsLimit; i++){
        imgThread[i].setSelfIndex(i);
        imgThread[i].start();
        }


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Ноября 28, 2011, 20:24
1) Надо верить "самому себе", (ну или "уважать себя" - смысл тот же). Мы сказали/утверждаем что каждая нитка работает со своей частью имеджа, таким образом нитки не пересекаются. Значит нехрен боязливо вставлять мутексы "на всякий случай" - тем более что вылетов они все равно никак не ловят.

2) По каким-то сторонним причинам мы не хотим делать нормальный контейнер указателей - но мы запрашиваем число ниток у пользователя. Ладно, так надо - значит надо, Вам виднее. Но тогда надо как минимум проверять не превысит ли введенное пользователем число ниток размер массива. Плюс называть вещи своими именами, а не так себе 
Код
C++ (Qt)
 // устанавливаем значения для потоков (это всё статические данные)
   imgThread[0].setBrightnessValue(ui->valueSpinBox->text().toInt()); // уровень яркости
   imgThread[0].setImagePointer(&image); // указатель на картинку
   imgThread[0].setTeamCount(threadsLimit); // всего потоков
 
Откуда видно что это static? Никак не видно. давайте так
Код
C++ (Qt)
   ImageThread::setBrightnessValue(ui->valueSpinBox->text().toInt());
   ImageThread::setImagePointer(&image);
   ImageThread::setTeamCount(threadsLimit);
 
Вот это static и это ясно без комментариев

3) Вылетает - нормально, у меня тоже ни одна multi-threaded задача сходу не пошла (на то она и  multi-threaded). Спокойно вставляем отладочную печать в run нитки, напр
Код
C++ (Qt)
printf("thread %p. image = %p (%d x %d) t_TeamCount = %d, t_SelfIndex = %d. begRow = %d, endRow = %d\n".
// здесь переменные
 

Др. словами - надо почиститься, навести порядок - и все получится (куда она денется)


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 29, 2011, 00:09
1) Когда я только начинал изучать потоки, вычитал, что доступ к совместно используемым данным, нужно блокировать мьютексом.
Ну вот это правило себе в голову сразу и вбил.
Собственно, да, в этом случае мьютексы и не нужны, можно их убрать.

2) Да, в программе задаётся массив ImageThread imgThread[4]; , а кол-во нужных потоков, пользователь выбирает сам. Пользователь не сможет задать более 4-х потоков, спасибо QSpinBox'у, который задаёт ограничение.

К слову о статических данных, тут Вы абсолютно правы, я недоглядел.

3) В каждой итерации второго (вложенного) цикла, вывожу отладочную информацию, такой строкой:
Код:
qDebug() << "#" << this->currentThreadId()
         << " img:" << &t_image
         << " team_count:" << t_TeamCount
         << " self_index:" << t_SelfIndex
         << " row:" << row
         << " col:" << column
         << " begRow:" << beginRow
         << " endRow:" << endRow;


Получаем следующий вывод. Первый запуск (2 потока). (в связи с большим кол-вом информации, часть заменена на "..."):
Код:
# 0x928  img: 0x41602c  team_count: 2  self_index: 0  row: 0  col: 0  begRow: 0  endRow: 97 
# 0x21c  img: 0x41602c  team_count: 2  self_index: 1  row: 97  col: 0  begRow: 97  endRow: 194
# 0x21c  img: 0x41602c  team_count: 2  self_index: 1  row: 97  col: 1  begRow: 97  endRow: 194
# 0x21c  img: 0x41602c  team_count: 2  self_index: 1  row: 97  col: 2  begRow: 97  endRow: 194
# 0x21c  img: 0x41602c  team_count: 2  self_index: 1  row: 97  col: 3  begRow: 97  endRow: 194
...
# 0x21c  img: 0x41602c  team_count: 2  self_index: 1  row: 97  col: 154  begRow: 97  endRow: 194
# 0x21c  img: 0x41602c  team_count: 2  self_index: 1  row: 97  col: 155  begRow: 97  endRow: 194
# 0x21c  img: 0x41602c  team_count: 2  self_index: 1  row: 97  col: 156  begRow: 97  endRow: 194
...
# 0x21c  img: 0x41602c  team_count: 2  self_index: 1  row: 100  col: 15  begRow: 97  endRow: 194
# 0x21c  img: 0x41602c  team_count: 2  self_index: 1  row: 100  col: 16  begRow: 97  endRow: 194
# 0x21c  img: 0x41602c  team_count: 2  self_index: 1  row: 100  col: 17  begRow: 97  endRow: 194
# 0x21c  img: 0x41602c  team_count: 2  self_index: 1  row: 100  col: 18  begRow: 97  endRow: 194
# 0x21c  img: 0x41602c  team_count: 2  self_index: 1  row: 100  col: 19  begRow: 97  endRow: 194
Программа неожиданно завершилась.


Второй запуск, 2 потока, другое изображение:
Код:
# 0x220  img: 0x41602c  team_count: 2  self_index: 0  row: 0  col: 0  begRow: 0  endRow: 302 
# 0x220  img: 0x41602c  team_count: 2  self_index: 0  row: 0  col: 1  begRow: 0  endRow: 302
# 0x220  img: 0x41602c  team_count: 2  self_index: 0  row: 0  col: 2  begRow: 0  endRow: 302
# 0xb74  img: 0x41602c  team_count: 2  self_index: 1  row: 302  col: 0  begRow: 302  endRow: 604
# 0xb74  img: 0x41602c  team_count: 2  self_index: 1  row: 302  col: 1  begRow: 302  endRow: 604
# 0xb74  img: 0x41602c  team_count: 2  self_index: 1  row: 302  col: 2  begRow: 302  endRow: 604
...
# 0xb74  img: 0x41602c  team_count: 2  self_index: 1  row: 302  col: 345  begRow: 302  endRow: 604
# 0xb74  img: 0x41602c  team_count: 2  self_index: 1  row: 302  col: 346  begRow: 302  endRow: 604
# 0xb74  img: 0x41602c  team_count: 2  self_index: 1  row: 302  col: 347  begRow: 302  endRow: 604
# 0xb74  img: 0x41602c  team_count: 2  self_index: 1  row: 302  col: 348  begRow: 302  endRow: 604
# 0xb74  img: 0x41602c  team_count: 2  self_index: 1  row: 302  col: 349  begRow: 302  endRow: 604
...
# 0xb74  img: 0x41602c  team_count: 2  self_index: 1  row: 302  col: 628  begRow: 302  endRow: 604
# 0xb74  img: 0x41602c  team_count: 2  self_index: 1  row: 302  col: 629  begRow: 302  endRow: 604
# 0xb74  img: 0x41602c  team_count: 2  self_index: 1  row: 302  col: 630  begRow: 302  endRow: 604
# 0xb74  img: 0x41602c  team_count: 2  self_index: 1  row: 302  col: 631  begRow: 302  endRow: 604
# 0xb74  img: 0x41602c  team_count: 2  self_index: 1  row: 302  col: 632  begRow: 302  endRow: 604
Программа неожиданно завершилась.


Дебаггер так же сообщает об ошибке сегментации.
Останавливается на строке
Код:
color.setRgb(qRed(pix), qGreen(pix), qBlue(pix));
И ещё пишет о *data <unavailable synchronous data>
и о &pix <not accessible>.

В отладочной информации, я не заметил ничего необычного, хотя...может плохо смотрел.


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Ноября 29, 2011, 10:39
1) Когда я только начинал изучать потоки, вычитал, что доступ к совместно используемым данным, нужно блокировать мьютексом.
Все Вы правильно вычитали, но у Вас "идеальный случай" когда можно (и нужно) обойтись без блокировок

3) В каждой итерации второго (вложенного) цикла, вывожу отладочную информацию, такой строкой:

Получаем следующий вывод. Первый запуск (2 потока). (в связи с большим кол-вом информации, часть заменена на "..."):
Код:
# 0x928  img: 0x41602c  team_count: 2  self_index: 0  row: 0  col: 0  begRow: 0  endRow: 97 
# 0x21c  img: 0x41602c  team_count: 2  self_index: 1  row: 97  col: 0  begRow: 97  endRow: 194
# 0x21c  img: 0x41602c  team_count: 2  self_index: 1  row: 97  col: 1  begRow: 97  endRow: 194
...
Оба-на - ведь должна быть одна печать на 1 нитку, и все. Почему вторая печатается много раз? Баг, разбирайтесь. И что значит "второго" - непонятно где тут "вложенный", поясните


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 29, 2011, 11:01
Ну как же?
Код:
  for(int row = beginRow; row < endRow; ++row){ // первый цикл
        ...
        for(int column = 0; column < t_image->width(); ++column){ // второй (вложенный)
            ...
            // вот ТУТ во втором цикле и вывожу отладочную информацию
            }
        }


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Ноября 29, 2011, 11:29
Нет, перенесите печать выше, сначала надо убедиться что все нитки "получили свои куски". Плюс последнюю строку (выдача сигнала) для отладки лучше закомментировать

Если случай "совсем тяжелый" и/или "надо срочно" - скиньте исходники, можно в личку


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 29, 2011, 12:25
Перенёс вывод отладочной информации в первый цикл, получил следующее:
Код:
# 0xfc8  img: 0x41602c  team_count: 2  self_index: 1  row: 302  begRow: 302  endRow: 604 
# 0xcc0  img: 0x41602c  team_count: 2  self_index: 0  row: 0  begRow: 0  endRow: 302
# 0xcc0  img: 0x41602c  team_count: 2  self_index: 0  row: 1  begRow: 0  endRow: 302
# 0xcc0  img: 0x41602c  team_count: 2  self_index: 0  row: 2  begRow: 0  endRow: 302
# 0xcc0  img: 0x41602c  team_count: 2  self_index: 0  row: 3  begRow: 0  endRow: 302
...
# 0xcc0  img: 0x41602c  team_count: 2  self_index: 0  row: 129  begRow: 0  endRow: 302
# 0xcc0  img: 0x41602c  team_count: 2  self_index: 0  row: 130  begRow: 0  endRow: 302
# 0xcc0  img: 0x41602c  team_count: 2  self_index: 0  row: 131  begRow: 0  endRow: 302
# 0xcc0  img: 0x41602c  team_count: 2  self_index: 0  row: 132  begRow: 0  endRow: 302
# 0xcc0  img: 0x41602c  team_count: 2  self_index: 0  row: 133  begRow: 0  endRow: 302
...
# 0xcc0  img: 0x41602c  team_count: 2  self_index: 0  row: 297  begRow: 0  endRow: 302
# 0xcc0  img: 0x41602c  team_count: 2  self_index: 0  row: 298  begRow: 0  endRow: 302
# 0xcc0  img: 0x41602c  team_count: 2  self_index: 0  row: 299  begRow: 0  endRow: 302
# 0xcc0  img: 0x41602c  team_count: 2  self_index: 0  row: 300  begRow: 0  endRow: 302
# 0xcc0  img: 0x41602c  team_count: 2  self_index: 0  row: 301  begRow: 0  endRow: 302
Программа неожиданно завершилась.

Случай не то, чтобы совсем уж тяжёлый, но проблематичный.
Исходники прямо сюда скину, у меня секретов нет.


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Ноября 29, 2011, 13:59
Собрал, посмотрел, все "как доктор прописал" (Picture 1) - только вот чего Вы wait закомментарили (Picture 2)? Так нельзя, главная нитка обязательно должна дождаться пока все рабочие завершатся. Оно конечно имя "wait" неинтуитивное (в оригинале pthread_join) но тем не менее.

К слову: не пишите русских комментариев, как правильно советует наш модератор (Picture 2). Рано или поздно "plain English" придется освоить, так что затягивать незачем.

Если вылет на др. имедже - загрузите, т.к. пока нечего искать


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 29, 2011, 17:24
чего Вы wait закомментарили?
Думал, что wait тут не нужен. Понятное дело, что в случае консольной программы, главный поток должен ждать завершения дочерних. Но вот не думал, что это нужно делать и в программах с GUI, т.к. главный поток не завершится после запуска дочерних.

Цитировать
не пишите русских комментариев. Рано или поздно "plain English" придется освоить
Да с Английским у меня проблем особых нет. В данном случае комментарии на Русском т.к. программа предназначена для слабой аудитории, которая не сильна ни в программировании, ни в Английском. По этому решил, что комментарии на Русском будут проще для восприятия.

Цитировать
Если вылет на др. имедже - загрузите, т.к. пока нечего искать
...Что-то не уловил мысль...


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Ноября 29, 2011, 19:28
Если вылет на др. имедже - загрузите, т.к. пока нечего искать
...Что-то не уловил мысль...
Ну просто пока Ваше приложение работает и не валится  :) Может вылетает на др исходных данных (имедже) так покажите на каком.

Примечание: менять "saturation" тоже очень полезно/наглядно, даже чаще нужно чем "value". Я бы добавил опцийку (совсем недавно писал такой шейдер). Ну и слайдеры бы неплохо смотрелись (впрочем дело вкуса)


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 29, 2011, 22:42
У Вас программа не падает? ...хм...да в чём же дело...

В папке images, 2 изображения. Что на первом, что на втором программа вылетает.
Вот например, image1, 2 потока - и программа падает.


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Ноября 30, 2011, 11:27
У Вас программа не падает? ...хм...да в чём же дело...

В папке images, 2 изображения. Что на первом, что на втором программа вылетает.
Вот например, image1, 2 потока - и программа падает.
Давайте имеджи, посмотрим по-живому. У меня (пока) все норм.


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 30, 2011, 14:27
...хм...странно получается...
вот картинки.

интересно разобраться, в чём же тут дело.


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Ноября 30, 2011, 17:28
Как программа повела себя у Вас с этими картинками?


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Декабря 01, 2011, 13:12
Нормально повела :) Единственное что я сделал - раскомментарил wait. По поводу workThread - он у Вас правильно вызывается, срабатывает QueuedConnection, но смысла немного, все равно надо "дождаться всех" и это время уже печатать (после wait). А если хотите иметь еще и время выполнения каждой, то проще сохранить в члене класса imageThread. Заодно присмотритесь к threadWorkDone, он объявлен с аргументом const QString & а для connect не так - во всяком случае проще сделать однообразно.


Название: Re: Многопоточное осветление пикселей
Отправлено: AlphaGh0St от Декабря 01, 2011, 21:51
Igors, представляете, под виндой компилировал и запускал программу, так она при работе более, чем в двух потоках вылетала. А сейчас, эксперимента ради, решил перекомпилировать и запустить под Линукс, и о чудо, всё заработало!
Программа прекрасно работает с разными изображениями и с разным количеством потоков.

Это, кончено, замечательно, но всё же не понятно, почему так произошло...

Igors, спасибо Вам за помощь!


Название: Re: Многопоточное осветление пикселей
Отправлено: daimon от Января 16, 2012, 16:33
под виндой на статике вылет, начиная уже с 2 потоков


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Января 16, 2012, 17:14
1) Проверьте что скомпилено как "Multithreaded DLL"
2) Закомментите отот emit workDone (он вообще "левый", зачем выводить имедж, если только одна нитка отстрелялась - ведь другие еще могут работать)
3) где-то t_Image калечится,  гляньте data, row, column и попробуйте отловить напр так

Код
C++ (Qt)
uchar * testScan = t_image.scanLine(0);  // до цикла
..
assert(t_image.scanLine(0) == testScan);  // в цикле перед setRgb
 


Название: Re: Многопоточное осветление пикселей
Отправлено: daimon от Января 17, 2012, 01:21
1) Проверьте что скомпилено как "Multithreaded DLL"
2) Закомментите отот emit workDone (он вообще "левый", зачем выводить имедж, если только одна нитка отстрелялась - ведь другие еще могут работать)
3) где-то t_Image калечится,  гляньте data, row, column и попробуйте отловить напр так

Код
C++ (Qt)
uchar * testScan = t_image.scanLine(0);  // до цикла
..
assert(t_image.scanLine(0) == testScan);  // в цикле перед setRgb
 

я специально ушел от рантайма, и скомпилил qt статикой и без рантайма
Код
C++ (Qt)
uchar * testScan = t_image->scanLine(0);  // до цикла
 
       for(int column = 0; column < t_image->width(); ++column){
           unsigned int &pix = data[column];
 
Q_ASSERT(t_image->scanLine(0) == testScan);  // в цикле перед setRgb
           color.setRgb(qRed(pix), qGreen(pix), qBlue(pix));
           color.getHsv(&h, &s, &v);
           v += t_brightnessValue; // значение, на которое надо увеличить яркость
           v = qMin(v, 255);
           color.setHsv(h, s, v);
 
           // сохраняем изменённый пиксельurrentThreadId() << " &pix:" << &pix << " pix:" << pix << " || row:" << row << " col:" << column;
           pix = qRgba(color.red(), color.green(), color.blue(), qAlpha(pix));
        }
ассерт не вылетает, но приложение вылетает

проблема здесь  unsigned int &pix = data[column];
по картинке видно, что вылет идёт на втором потоке - осветлена половина


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Января 17, 2012, 13:34
- Перенесите (первый) testScan выше, до цикла по строкам
- отключите emit workDone, наиболее вероятно там порылась собака
- значения переменных на момент вылета (row, column, dat)?


Название: Re: Многопоточное осветление пикселей
Отправлено: daimon от Января 17, 2012, 14:51
- Перенесите (первый) testScan выше, до цикла по строкам
- отключите emit workDone, наиболее вероятно там порылась собака
- значения переменных на момент вылета (row, column, dat)?

если емит убираю, оно не выводит результат на экран


Название: Re: Многопоточное осветление пикселей
Отправлено: Igors от Января 17, 2012, 15:20
если емит убираю, оно не выводит результат на экран
Так выведите после того как все нитки отработали.

Ну а с вылетом-то что? Где Вы учились на партизана? Так не можнА  :)


Название: Re: Многопоточное осветление пикселей
Отправлено: Fregloin от Января 18, 2012, 12:49
здесь бы в тему был как раз OpenCL!


Название: Re: Многопоточное осветление пикселей
Отправлено: lolbla2 от Февраля 25, 2012, 19:16
- Перенесите (первый) testScan выше, до цикла по строкам
- отключите emit workDone, наиболее вероятно там порылась собака
- значения переменных на момент вылета (row, column, dat)?

если емит убираю, оно не выводит результат на экран

Вопрос не по теме, но всё же: как Вам удалось компилить программу на Qt в MSVS ? ???


Название: Re: Многопоточное осветление пикселей
Отправлено: LisandreL от Февраля 25, 2012, 20:00
Вопрос не по теме, но всё же: как Вам удалось компилить программу на Qt в MSVS ?
А в чём проблема?
Поддержка компиляторов MS VC 2005/2008/2010 сейчас идёт в составе Qt SDK.
Ну а если разрабатывать в студии хочется, то есть Qt VS Add-in для студий выше экспресса.


Название: Re: Многопоточное осветление пикселей
Отправлено: lolbla2 от Февраля 26, 2012, 09:58
Вопрос не по теме, но всё же: как Вам удалось компилить программу на Qt в MSVS ?
А в чём проблема?
Поддержка компиляторов MS VC 2005/2008/2010 сейчас идёт в составе Qt SDK.
Ну а если разрабатывать в студии хочется, то есть Qt VS Add-in для студий выше экспресса.

Ну да получается в студию (в саму IDE) можно встроить Qt библиотеки? Меня конечно и Qt Creator устраивает, но просто удивило, не знал что так можно...


Название: Re: Многопоточное осветление пикселей
Отправлено: alexksv2010 от Февраля 29, 2012, 13:19
Если вопрос еще не решен, то столкнулся со схожей проблемой...
И решил ее следующим образом:
1.  Контейнерами: Ошибка: Программа почему-то обнуляла контейнер (Несмотря на то, что кроме потока с ним никто не работал) Решил это просто заперев функцию  мьютексами QMutex mutex.lock() вначале и mutex. unlock() в конце.
2. Общение из потока с главным потоком приводит к тому, что сигнал не всегда генерируется... Решил с помощью:
class RequestEvent:public QEvent
{
public:
    PointArray val;
    RequestEvent(PointArray vl);
};

QCoreApplication::postEvent(parent,new RequestEvent(request),Qt::HighEventPriority);