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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Поток для работы с диском  (Прочитано 6862 раз)
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« : Май 18, 2013, 15:05 »

Как наиболее правильно и просто реализовать класс для работы с диском в другом потоке(чтение и сохранение файлов). Когда программа посылает запрос на чтение она продолжает выполняться, и как только файл будет загружен в память она получит указатель на него. Файлов может быть много и они могут долго загружаться, в это время программа будет постоянно обновлять сцену на opengl.

У класса должен быть список задач, для того чтобы прервать все или некоторые задачи, когда класс неипользуется поток не должен нагружать ядро процессора.
« Последнее редактирование: Май 18, 2013, 15:13 от deMax » Записан
mutineer
Гость
« Ответ #1 : Май 18, 2013, 15:25 »

Пишешь класс, отправляешь его в QThread и используешь
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #2 : Май 18, 2013, 15:31 »

Тогда такие вопросы, как только класс закончил выполнять действия он останавливается, как только появились новые запросы класс запускается.
Через qtconcurrent это не лучше сделать?
Записан
mutineer
Гость
« Ответ #3 : Май 18, 2013, 15:31 »

Зачем? Пустой ивент-луп не так чтобы очень сильно CPU грузит, сидит себе и ждет новых событий
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #4 : Май 18, 2013, 16:01 »

Может есть готовый пример? Задача общая для потоков.
Наследование от QThreat в моем случае не красиво.
http://habrahabr.ru/post/150274/
Цитировать
«Класс QThread создан и предназначен для использования в качестве интерфейса к потокам операционной системы, но не для того, чтобы помещать в него код, предназначенный для выполнения в отдельном потоке. В ООП мы наследуем класс для того чтобы расширить или углубить функциональность базового класса. Единственное оправдание для наследования QThread, которое я могу представить, это добавление такой функциональности, которой в QThread не существует, например, передача указателя на область памяти, которую поток может использовать для своего стека, или, возможно, добавление поддержки интерфейсов реального времени. Загрузка файлов, работа с базами данных, и подобные функции не должны присутствовать в наследуемых классах QThread; они должны реализовываться в других объектах»

Для меня красивое решение - это класс A c методом Get(int a, int *b); Я вызываю сколько угодно раз этот очень медленный метод, как только он просчитает значение в другом потоке оно появится в переменной b.
« Последнее редактирование: Май 18, 2013, 16:05 от deMax » Записан
mutineer
Гость
« Ответ #5 : Май 18, 2013, 16:03 »

Я не говорил про наследование от QThread, я как раз говорил от него не наследоваться
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #6 : Май 18, 2013, 17:03 »


Для меня красивое решение - это класс A c методом Get(int a, int *b); Я вызываю сколько угодно раз этот очень медленный метод, как только он просчитает значение в другом потоке оно появится в переменной b.


Можно так, например:
Код
C++ (Qt)
#include <iostream>
#include <future>
#include <functional>
 
struct worker {
   int get(int a) {
       return a*a*a*a*a*a*a;
   }
};
 
int main()
{
   worker w;
   auto res = std::async(std::launch::async, std::bind(std::function<int (worker &, int)>(&worker::get), w, 2));
 
   std::cout << res.get() << std::endl;
   return 0;
}
 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
mutineer
Гость
« Ответ #7 : Май 18, 2013, 17:08 »


Для меня красивое решение - это класс A c методом Get(int a, int *b); Я вызываю сколько угодно раз этот очень медленный метод, как только он просчитает значение в другом потоке оно появится в переменной b.


Ну так сделай такой класс со слотом Get(...), который внутри складывает данные в очередь, выбирает из очереди данные и выполняет работу. По окончанию высылает сигнал со значением. А объект этого класса при помощи moveToThread вынеси в отдельный поток.
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #8 : Май 19, 2013, 14:23 »

Можно так, например:
А это будет работать последовательно если я в цикле запрос сделаю?
Код:
for(int i=0; i<100; ++i)
 auto res = std::async(std::launch::async, std::bind(std::function<int (worker &, int)>(&worker::get), w, 2));


Примерно так я вижу использование данного класса:
Код:
Storage storage;
QImage *img[100];
int error[100]; //  опционально, код ошибки операции, если операция выполняется указатель пустой

for (int i=0; i<100; ++i) storage.load(QString("%1.jpg").arg(i), &img[i], *error[i]);

...

while(1)
   for(int i=0; i<100; ++i)
      if(img[i] && !err[i])
           painter.draw(0,0,img[i]);

...

Чтение картинки в отдельном потоке это обычный
QImage *tmp = new QImage(fileName);
img = tmp;

« Последнее редактирование: Май 19, 2013, 15:08 от deMax » Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #9 : Май 19, 2013, 18:47 »

Можно так, например:
А это будет работать последовательно если я в цикле запрос сделаю?
Код:
for(int i=0; i<100; ++i)
 auto res = std::async(std::launch::async, std::bind(std::function<int (worker &, int)>(&worker::get), w, 2));


Не.. так делать не надо.. std::async - запускает функцию в отдельном потоке (если установлен флаг std::launch::async) Всё.
Она хороша там, где, например, можно без особых проблем распараллелить какой-нибудь алгоритм. Например, если нужно посчитать интеграл методом Монте Карло или какую-нибудь сумму или.. Ну в общем всё то, что можно разбить на конечное число частей и параллельно их сосчитать.

Посмотрите лучше примеры по QThread (раз у вас тут всё на Qt замешано).   
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #10 : Май 22, 2013, 07:27 »

Мой helloworld

cachedisk.cpp
Код:
#include "cachedisk.h"

#include <QTabWidget>

CacheDisk::CacheDisk()
{
//    connect(this, SIGNAL(Finish()), this, SLOT(Finished()), Qt::QueuedConnection);
    worked = false;
}

void CacheDisk::Read(QString fileName, QPixmap **pix)
{
    taskList.append(QPair<QString, QPixmap**>(fileName,pix));

    if(!worked) {
        worked = true;
        QPair<QString, QPixmap**> param = taskList.takeFirst();

        pixSave = param.second;

        future = QtConcurrent::run(this, &CacheDisk::ReadInThread, param.first, param.second);
        futureWather.setFuture(future);
        connect(&futureWather, SIGNAL(finished()), this, SLOT(Finished()));
//        ReadInThread(param.first, param.second);
    }
}

void CacheDisk::Finished()
{
    *pixSave = future.result();
    qDebug()<<"finish"<<*pixSave;


    QLabel *l = new QLabel;
    l->setPixmap(**pixSave);
    l->show();

    worked = false;

    if(!taskList.empty()) {
        worked = true;
        QPair<QString, QPixmap**> param = taskList.takeFirst();
        QtConcurrent::run(this, &CacheDisk::ReadInThread, param.first, param.second);
    }
}

QPixmap* CacheDisk::ReadInThread(QString fileName, QPixmap **pix)
{
    QPixmap *tmpPixmap = new QPixmap(fileName);
qDebug()<<tmpPixmap;

    return tmpPixmap;
}

cachedisk.h
Код:
#ifndef CACHEDISK_H
#define CACHEDISK_H

#include <QObject>
#include <QtConcurrentRun>
#include <QImage>
#include <QPixmap>
#include <QLabel>
#include <QFutureWatcher>

class CacheDisk: public QObject
{
    Q_OBJECT
    QPixmap **pixSave;
    QList<QPair<QString,QPixmap**> > taskList;

    QPixmap *ReadInThread(QString fileName, QPixmap **pix);
    bool worked;

    QFuture<QPixmap*> future;
    QFutureWatcher<QPixmap*> futureWather;

private slots:
    void Finished();

public:
    CacheDisk();
    void Read(QString fileName, QPixmap **pix);
};

#endif // CACHEDISK_H


main.cpp
Код:
#include <QApplication>
#include <QPixmapCache>
//#include "zzz.h"
//#include "diskcache.h"
#include "cachedisk.h"
#include <QtGui>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    CacheDisk cacheDisk;
    QPixmap *pix = 0;
    cacheDisk.Read("D:/WORK/learn/1.jpg", &pix);

    return app.exec();
}


Не отображает картинку, вначале QLabel был в main.cpp, если вызвать метод read без потока то все загружается, если в потоке то не работает, хотя адрес возвращает на картинку.
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #11 : Май 22, 2013, 11:10 »

Если заменить
    QPixmap *tmpPixmap = new QPixmap(fileName);
на
    QPixmap *tmpPixmap = new QPixmap;
    qDebug()<<tmpPixmap->load(fileName);
то работает для другого потока, а в том же потоке работает и первый вариант.

qt выдает предупреждение "QPixmap: It is not safe to use pixmaps outside the GUI thread" стоит использовать QPixmap или перейти на QImage?
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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