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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: удаление стека потока  (Прочитано 4976 раз)
define
Гость
« : Июль 20, 2011, 17:27 »

имеется поток:
Код:
/* QImage* image;*/
ShowImage::ShowImage()
{
    stop_flag=false;
}

void ShowImage::run()
{
    //для уничтожения потока
    setTerminationEnabled(true);

    AdvImage tmp = list->at(pos);

    image=new QImage(tmp.getPath());//tmp.getPath() - путь к изображению

    int temp_h = image->size().height();
    int temp_w = image->size().width();

    if(temp_w>temp_h)//сравнение ширины и высоты изображения
    {
        temp_h=_h;
        _h=_w;
        _w=temp_h;
    }

    *image = image->scaled(_w,_h);
    label->setPixmap(QPixmap::fromImage(*image));
    QString s = "image is displayed";
    qDebug(s.toStdString().c_str());

}

void ShowImage::stop()
{
    image->~QImage();
    stop_flag=true;
}

void ShowImage::setValues(QLabel* img, QList<AdvImage> *_list, int index, int h, int w)
{
     list = _list;
     label=img;
     _h=h;
     _w=w;
     pos=index;

}

Вызов этого потока:
Код:
/*ShowImage *showimage_storage;*/
void viewer::show_image(int pos)
{
    position = pos;
    if(showimage_storage->isRunning())
    {
        showimage_storage->stop();
        showimage_storage->terminate();
    }
    showimage_storage->setValues(image,image_storage,position,h,w);
    QString s = "start displayed image";
    qDebug(s.toStdString().c_str());
    showimage_storage->start();
}

Проблема в следующем:
в
Код:
image=new QImage(tmp.getPath());//tmp.getPath() - путь к изображению
поступает большое изображение (30мб+) и начинает грузить в оперативную память. При вызове terminate поток удаляется, но память после него не чистится.
Итак вопрос: как насильно можно отчистить стек в потоке?
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


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


Просмотр профиля WWW
« Ответ #1 : Июль 20, 2011, 18:02 »

connect (showimage_storage, SIGNAL (terminated ()), showimage_storage, SLOT (deleteLater ()));
и в деструкторе ShowImage удаляешь картинку.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Июль 20, 2011, 18:37 »

Проблема в следующем:
в
Код:
image=new QImage(tmp.getPath());//tmp.getPath() - путь к изображению
поступает большое изображение (30мб+) и начинает грузить в оперативную память. При вызове terminate поток удаляется, но память после него не чистится.
Итак вопрос: как насильно можно отчистить стек в потоке?
Наверное Вы хотели сказать 300мб+ (30 то так, кот наплакал). Вы делаете то что не то чтобы "нельзя" а "не нужно" делать - просто потому что себе дороже. Насильное завершение нитки - хороший способ нажить себе кучу забот и потом их долго разгребать. Чего Вы хотите от нитки? Чтобы она в фоне грузила имедж и (если нужно) его скалила. Ну и сделайте напр так
Код
C++ (Qt)
class MyImageLoader : public QThread {
public:
...
QImage mImage;
bool mStopFlag;
 
virtual void run( void )
{
 mImage.load(tmp.getPath());
 int h = mImage.height();
 if (!mStopFlag && !mImage.isNull() && mImage.width() > h)
  mImage = mImage.scaled(h, h);
}
};
 
И вся любовь с той ниткой. А сами спокойно поджидаете на слоте когда она отстреляется (сигнал finished), забираете готовый имедж, куда надо его в UI ставите и удаляете объект MyImageLoader. Чистить ничего не требуется. Понятно что хочется прервать загрузку имеджа в любой момент - но ничего, перехочется
Записан
define
Гость
« Ответ #3 : Июль 20, 2011, 19:08 »

К сожалению задача стоит вполне конкретная Грустный
Код:
В конструкторе:
    showimage_storage = new ShowImage();
    connect (showimage_storage, SIGNAL (terminated ()), showimage_storage, SLOT (deleteLater ()));

void viewer::show_image(int pos)
{
    position = pos;
    if(showimage_storage->isRunning())
    {
        showimage_storage->stop();
        showimage_storage->terminate();
        showimage_storage = new ShowImage();
        connect (showimage_storage, SIGNAL (terminated ()), showimage_storage, SLOT (deleteLater ()));
    }
    showimage_storage->setValues(image,image_storage,position,h,w);
    QString s = "start displayed image";
    qDebug(s.toStdString().c_str());
    showimage_storage->start();

}

Сам метод:
Код:
ShowImage::~ShowImage()
{
    image->~QImage();
}

void ShowImage::run()
{
    //для уничтожения потока
    setTerminationEnabled(true);
...
    image = new QImage(tmp.getPath());
...
}
В дебаге деструктор вроде как выполняется, но память по-прежнему не освобождается Плачущий
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #4 : Июль 20, 2011, 19:40 »

image->~QImage();
Это что за изобретение?
delete image;

Но тут всё намного  хуже. terminate - это аварийное завершение потока и может его прервать где угодно, соответственно и память может утекать где угодно.
Для штатного завершения потока его использовать не следует.
Записан
zenden
Гость
« Ответ #5 : Июль 21, 2011, 10:36 »

А причем тут вообще стек?
У вас картинка ведь  в куче выделяется.

Если вам уж так хочется использовать ужасный метод terminate(), то сохраняйте где-то предварительно указатель на вашу картинку и удаляйте её в главном потоке. 
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Июль 21, 2011, 13:50 »

Но тут всё намного  хуже. terminate - это аварийное завершение потока и может его прервать где угодно, соответственно и память может утекать где угодно.
То было бы еще ничего если только "утечки". Но после насильного прерывания QImage может вообще остаться уродом который рухнет на delete.

К сожалению задача стоит вполне конкретная Грустный
Ну то дело Ваше (и Вашего проекта) какие задачи ставить. По ходу дела еще 2 детали

1) Работа с UI не из главной нитки
Код:
void ShowImage::run()
{
...
    label->setPixmap(QPixmap::fromImage(*image));
...
}

2) Между загрузкой имеджа и его масштабированием легко провериться на отмену (флажок) и 100% корректно выйти. Масштабирование также может быть сделано по частям с выводом кусков - здесь проблем нет.
Записан
define
Гость
« Ответ #7 : Июль 21, 2011, 14:40 »

Между загрузкой имеджа и его масштабированием легко провериться на отмену (флажок) и 100% корректно выйти.
Именно так и сделал. Спасибо всем.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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