Russian Qt Forum
Ноябрь 22, 2024, 23:22 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: GUI-thread и Child-threads  (Прочитано 13989 раз)
HunteX
Гость
« : Май 17, 2011, 12:43 »

Здравствуйте! Есть форма с парой кнопок. При нажатии на кнопку должен создаваться поток, в котором будет происходить загрузка большого изображения (впринципе, тип работы не особо важен, главное, что работать будет долго, именно поэтому не хотелось бы, чтобы основной поток зависал). Я новичек в Qt, на C# я без проблем напишу, а с кьюти пока не совсем разобрался ... Просьба такая: накидайте небольшой (как можно проще) шаблончик, который будет выполнять действия, описанные мною выше. Спасибо!

С Уважением, Андрей.

p.s. конечно же предполагается загрузка не одного изображения, а нескольких ... вообщем нужен шаблон использования некого аналога ThreadPool в .NET
« Последнее редактирование: Май 17, 2011, 12:45 от HunteX » Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #1 : Май 17, 2011, 13:02 »

Читай
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
HunteX
Гость
« Ответ #2 : Май 17, 2011, 14:34 »


Не сомневался Улыбающийся
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #3 : Май 17, 2011, 15:09 »

Фигасе, 30 долларов за книжку по каким-то тредам...
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Май 17, 2011, 15:53 »

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

По существу - "кидать" особо нечего. Запихиваете свою содержательную часть в run QThread (наследуетесь), толкаете его с помощью метода start, принимаете результаты по сигналу finished - ну или (если есть необходимость) ждете методом wait. То есть у Вас легкое/приятное "многопоточное программирование"
Записан
HunteX
Гость
« Ответ #5 : Май 17, 2011, 16:28 »

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

По существу - "кидать" особо нечего. Запихиваете свою содержательную часть в run QThread (наследуетесь), толкаете его с помощью метода start, принимаете результаты по сигналу finished - ну или (если есть необходимость) ждете методом wait. То есть у Вас легкое/приятное "многопоточное программирование"

Спасибо за совет! У меня пара вопросов:
Цитировать
Запихиваете свою содержательную часть в run QThread
Код:
void Thread::run(Object *myobject); // так можно ?

Цитировать
принимаете результаты по сигналу finished
А вот тут можно по подробнее?

Если я передаю Thread::run(...) некий НЕ глобальный параметр, как я могу получить результат? Если объект глобальный - тут все понятно: можно послать событие о завершении Thread::run() и потом обратися к этому глобальному объекту - результату работы Thread::run(). А как быть с локальным объектом ?
Записан
ieroglif
Гость
« Ответ #6 : Май 17, 2011, 16:31 »

создай свой класс, наследующий QThread, переопредели в нём run() метод, в котором опиши действия выполняемые потоком (загрузка картинок)
создай объект своего класса, вызови ему start()
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Май 17, 2011, 16:48 »

Код:
void Thread::run(Object *myobject); // так можно ?
Нет, т.к. run - virtual метод. Во многих случаях хороший выбор - вообще не трогать run (по умолчанию он запускает eventLoop) а посылать ему сигналы (типа "нитка - а сделай мне то-то"). В сигналах можно указывать любые параметры  

А вот тут можно по подробнее?

Если я передаю Thread::run(...) некий НЕ глобальный параметр, как я могу получить результат? Если объект глобальный - тут все понятно: можно послать событие о завершении Thread::run() и потом обратися к этому глобальному объекту - результату работы Thread::run(). А как быть с локальным объектом ?
Выберите стратегию/метод что Вам нравится. Типичные случаи

- нитка запускается для решения одной/конкретной задачи. Перекрываете run и заряжаете параметры напр в конструкторе нитки

- нитка принимает события (может быть использована для решения одной или многих (разных) задач) - подаете параметры в сигнале

Как получить результат. Самое простое - по сигналу который испустит сама нитка когда сделает все что нужно. Если от нее ничего больше не требуется - задействовать стандартный сигнал finished
« Последнее редактирование: Май 17, 2011, 16:52 от Igors » Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #8 : Май 17, 2011, 16:51 »

Есть еще QtConcurrent, можешь его заюзать.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
HunteX
Гость
« Ответ #9 : Май 17, 2011, 18:55 »

Есть еще QtConcurrent, можешь его заюзать.
Я с него начал, даже сделал то, что надо наполовину, но показалось слишком сложно и я удалил код Улыбающийся

Вот, набросал класс (не ругайте сильно, так как я новичек не только в Qt, но и в C++, да и про ООП все позабывал, сейчас вспоминаю):

header
Код:
#include <QThread>
#include "cv.h"
#include "highgui.h"
#include <Magick++.h>

using namespace Magick;

class ThreadClass : QThread
{
Q_OBJECT

public:
ThreadClass(char *in_imagePath, int in_scaleWidth, int in_scaleHeight);

private slots:
// тут тоже что-то должно быть ...

protected:
void run(); // запуск потока

public:
volatile bool isLoadingDone;
volatile bool isScaledDone;

QGraphicsScene *scene;

private:
void OpenImage(); // открытие изображения
void ScaleImage(); // масштабирование изображения

char* imagePath;
Magick::Image *imImage;

int scaleWidth, scaleHeight;
};

source
Код:
#include "megatransformer.h"
#include "HunteXThreadClass.h"
#include "IplImageToQImage.h"
#include "OpenCVMagickPP.h"

ThreadClass::ThreadClass(char *in_imagePath, int in_scaleWidth, int in_scaleHeight)
{
imagePath = in_imagePath;
scaleWidth = in_scaleWidth;
scaleHeight = in_scaleHeight;

// вообщем-то флаги по умолчанию равны false
// дурная привычка задавать все поля в конструкторе :)
isLoadingDone = false;
isScaledDone = false;
}

void ThreadClass::run()
{
OpenImage();

//

ScaleImage();
}

void ThreadClass::OpenImage()
{
imImage->read(imagePath);

isLoadingDone = true;
// тут видимо надо отправить
}

void ThreadClass::ScaleImage()
{
Magick::Image *scaledImage(imImage);

scaledImage->resize(Magick::Geometry(scaleWidth, scaleHeight));
scaledImage->profile("*", Blob());

QImage *qi = IplImageToQImage(MagickImageToIplImage(scaledImage), 0);

QPixmap pixmap = QPixmap::fromImage(*qi);
QPixmap sized = pixmap.scaled(this->scaleWidth, this->scaleHeight);

scene->clear();
scene->addPixmap(sized);

delete qi;

isScaledDone = true;
}

К примеру, у меня есть функция (пускай будет foo()), в которой я получаю пути всех картинок (при помощи QFileDialog::getOpenFileNames()), как мне юзать мой класс? Догадываюсь, что для каждой картинки придется создавать объект ThreadClass и засовывать его в пул потоков ... я правильно понял? И еще помогите разобраться с сигналами и слотами ... Вопросы такие:
1. Где именно надо вызывать connect? (думаю, что в функции foo(), после создания объекта ThreadClass?)
2. Как получить событие, что функция ThreadClass::OpenImage() закончила свою работу? (наверное я зря их сделал private?)

Спасибо!
« Последнее редактирование: Май 17, 2011, 18:58 от HunteX » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Май 18, 2011, 06:52 »

1. Где именно надо вызывать connect? (думаю, что в функции foo(), после создания объекта ThreadClass?)
Да
2. Как получить событие, что функция ThreadClass::OpenImage() закончила свою работу? (наверное я зря их сделал private?)
Просто посылаете сигнал из run в главную нитку (connect с типом QueuedConnection)

Догадываюсь, что для каждой картинки придется создавать объект ThreadClass и засовывать его в пул потоков ... я правильно понял?
Я бы не связывался с пулом а сделал бы простую очередь. Создаете структуру/класс с теми полями что Вы сделали для ThreadClass, допустим CTask. Толкаете N ниток (idealThreadCount), run выглядит примерно так

Код
C++ (Qt)
void ThreadClass::run( void )
{
 while (true) {
  theSemaphore.acquire(); // ждем заданий от главной нитки
  theMutex.lock();            // извлекаем задание
  CTask task = theTaskList.takeAt(0);
  theMutex.unlock();
 
  if (task.imagePath == NULL)  break;  // пустое имя значит завершить нитку
  task.OpenImage();  // занимаемся имеджем
  emit signalLoad(task.imagePath); // сообщаем что загрузили
  task.ScaleImage();  // масштабим
  emit signalScaled(task.imImage); // сообщаем что готово
 }  
}
 
А главная нитка помещает в очередь
Код
C++ (Qt)
void AddImage2Process( const CTask & task )
{
 QMutexLocker locker(&theMutex);
 theTaskList.push_back(task);
 theSemaphore.release();   // есть работа для ниток-загрузчиков
}
 
И еще
scene->clear();
scene->addPixmap(sized);
Убедитесь что эти вызовы "потокобезопасны" иначе перенесите их в главную нитку
« Последнее редактирование: Май 18, 2011, 10:06 от Igors » Записан
HunteX
Гость
« Ответ #11 : Май 18, 2011, 09:25 »

То есть в начале из GUI-потока вызывается функция ThreadClass::AddImage2Process(), после чего выполняется ThreadClass::run() ?

Код:
CMutexLocker locker(&theMutex);
А вот насчет этого я не совсем понял: нужно отдельный класс создавать для хранения мьютекса ? То есть не совсем понятно, зачем это нужно и что выполняет этот класс и как он выглядит ... возможно имелся ввиду QMutexLocker ?

p.s. Спасибо за код! Я только начинал разбираться и хотелось бы с начала написать правильный велосипед Улыбающийся
« Последнее редактирование: Май 18, 2011, 09:49 от HunteX » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Май 18, 2011, 10:10 »

То есть в начале из GUI-потока вызывается функция ThreadClass::AddImage2Process(), после чего выполняется ThreadClass::run() ?
Необов'язково. Если у run нет работы - он будет ждать на семафоре. AddImage2Process делает главная нитка (а не ThreadClass)

А вот насчет этого я не совсем понял: нужно отдельный класс создавать для хранения мьютекса ? То есть не совсем понятно, зачем это нужно и что выполняет этот класс и как он выглядит ... возможно имелся ввиду QMutexLocker ?
Да, "очепятка", подправил  Улыбающийся
Записан
HunteX
Гость
« Ответ #13 : Май 18, 2011, 11:01 »

То есть в начале из GUI-потока вызывается функция ThreadClass::AddImage2Process(), после чего выполняется ThreadClass::run() ?
Необов'язково. Если у run нет работы - он будет ждать на семафоре. AddImage2Process делает главная нитка (а не ThreadClass)

А вот насчет этого я не совсем понял: нужно отдельный класс создавать для хранения мьютекса ? То есть не совсем понятно, зачем это нужно и что выполняет этот класс и как он выглядит ... возможно имелся ввиду QMutexLocker ?
Да, "очепятка", подправил  Улыбающийся

А значит, необходимо передавать в класс ThreadClass семафор и мьютекс ... скажем в конструкторе ThreadClass() ?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Май 18, 2011, 11:18 »

А значит, необходимо передавать в класс ThreadClass семафор и мьютекс ... скажем в конструкторе ThreadClass() ?
Просто сделать их static членами ThreadClass, т.к. они должны использоваться всеми нитками которые грузят имеджи
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.099 секунд. Запросов: 23.