Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt Общие вопросы _ Выполнение произвольной фунции в отдельном потоке

Автор: kuler 28.10.2008, 15:19

не в QThread, чтоб как в паскале. Sleep(200) и ништяк (без таймеров)

Автор: ViGOur 28.10.2008, 15:22

Насколько я знаю можно только или таймер или QThread, по другому вроде как нельзя... :(

Автор: Litkevich Yuriy 28.10.2008, 15:26

непонятно для каких целей. Хочешь убить ГУЙ на время или для отладки, если для отладки в классе QTest, есть такая функция:
void QTest::qSleep ( int ms )
и
void QTest::qWait ( int ms ) [static]

Автор: kuler 28.10.2008, 15:44

а есть какая то хрень (типа вроде waitforobject) - это когда поток запустил, вызвал эту функцию и код остановился пока поток не завершится

Автор: Litkevich Yuriy 28.10.2008, 15:54

см. QWaitCondition

Автор: kuler 28.10.2008, 16:03

а как сделать чтоб не разывать функцию:

func()
{
  method1() in thread

  if (thread->finished)
  {
    method2() in thread
     и тд

  }
}

Автор: Litkevich Yuriy 28.10.2008, 16:17

kuler, не дошло, по подробнее пожалуйста.

Автор: kuler 28.10.2008, 16:31

ну обычно идет
метод1()
метод2() - выполняется после полного завершения мет1

если с потоками то
рун(метод1)
метод2() - выполняется сразу после запуска потока, но данные необходимые для его работы еще не сформированы потоком, поэтому косяк.

для этого делается
рун(метод1)
ждем когда он завершится
после этого выполняем метод2()

но нужно чтоб жуй функционировал

Автор: Litkevich Yuriy 28.10.2008, 16:40

яб так сделал, создал наследника от QThread:

Раскрывающийся текст
class MyThread : public QThread
{
    Q_OBJECT

public:
    MyThread();
    ~MyThread();
    
    void method_1();
    void method_2();

protected:
    void run();

};


...
...
...
void MyThread::method_1()
{
...
}

void MyThread::method_2()
{
...
}

void ThreadSend::run()
{
    method_1();
    method_2();
}


где-то в основном коде программы:
MyThread    *mt;
    
    mt->start(QThread::LowestPriority);

Автор: ViGOur 28.10.2008, 16:42

А чем это не подходит?

void QMyThread::run() 
{
   metod1();
   metod2();
   metod3();
}
методы будут выполняться друг за другом и в потоке.

Автор: kuler 28.10.2008, 16:55

слегка не подходит тем что может быть дофига всяких комбинаций методов

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

Автор: anonymous 28.10.2008, 17:05

Цитата(kuler @ 28.10.2008, 16:55) *
слегка не подходит тем что может быть дофига всяких комбинаций методов

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


Глянь http://www.prog.org.ru/topic_5140_0.html или http://www.prog.org.ru/topic_3662_0.html

Автор: Litkevich Yuriy 28.10.2008, 17:25

2 Гость_anonymous_*, ему всетаки не задержка нужна, перво причина:
выполнить несколько произвольных функций, подряд, в нутри некого класса. Причем функции могут этому классу не принадлежать. А ГУЙ недолжен умереть.

kuler, я правильно понял?

Автор: kuler 28.10.2008, 18:20

да, хотелось бы как то вообще просто делать - типа запускаешь функцию и говоришь "в отдельном потоке" и не надо никаких run. Ибо нужно к примеру 20 разных функций в потоках вызывать (по отдельности), не делать же теперь двадцать классов, потомков потока, можно свитчем делать - тоже некрасиво, и передачу параметров просто так не осуществишь.

Автор: Litkevich Yuriy 28.10.2008, 19:41

У меня крутится в голове мысль, но она только на половинку :) Вторую половинку надо додумать.

Итак:
Надо оставить тот класс который я привел (MyTread), в нем нужно реализовать функцию типа "жуй (ешь)", а также один сигнал "готово".
В своем класе зарание создаешь слот и соеденяешь его с сигналом MyTread::готово(). И создаешь объект типа MyTread, передаешь в функцию "жуй" другую функцию, которую пожевать надо.
Функция "жуй" говорит собственному классу (MyTread) какая функция находится в нутри MyTread::run() и вызывает метод QTread::start()
Ты в это время что-то полезное делаешь в своем классе.
Когда выполнится целевая функция посылается сигнал "готово".
При срабатывании слота, если необходимо, говоришь опять "жуй" с новой функцией.

P.S. выделенное курсивом надо додумать. А метода получается универсальной, т.е. в других классах/программах можно повторно использовать.
(собственно как функцию передовать? Функция произвольная - указатель какой-то универсальный надо)

P.P.S. Тему переименовал, ближе к задаче.

Есть такой метод:
void QObject::moveToThread ( QThread * targetThread )
может есть и готовый для конкретных функций, надо поковырятся в асистенте.

Автор: kuler 29.10.2008, 10:31

Litkevich Yuriy,
а как предлагаешь параметры в функцию передавать? а в готово будет switch, тк сценарии действия после вызова разных функций различны

Автор: Tonal 29.10.2008, 11:33

Цитата
QFuture<T> QtConcurrent::run ( Function function, ... )

Runs function in a separate thread. The thread is taken from the global QThreadPool. Note that the function may not run immediately; the function will only be run when a thread is available. ...

Оно?

Да, ждать пока выполнится функция в другом потоке чтобы гуй не замерзал нужно или крутя Application->processEvents() или опрашивая статус завершения по таймеру или в идле.

Автор: Litkevich Yuriy 29.10.2008, 11:42

Цитата(Tonal @ 29.10.2008, 14:33) *
QtConcurrent
Жаль это толко в Qt 4.4.*, я еще толком про этот класс не читал.

Автор: kuler 29.10.2008, 13:02

Цитата(Tonal @ 29.10.2008, 11:33) *
или в идле.

это чо такое?

Автор: Litkevich Yuriy 29.10.2008, 13:56

Цитата(kuler @ 29.10.2008, 16:02) *
это чо такое?
idl

Автор: kuler 29.10.2008, 14:07

Цитата(Litkevich Yuriy @ 29.10.2008, 13:56) *
idl

a это? :blink:

Автор: Litkevich Yuriy 29.10.2008, 14:24

очепятался немного
idle - простой/ничего не деланье

Автор: Tonal 1.11.2008, 13:56

Цитата(kuler @ 29.10.2008, 16:02) *
Цитата(Tonal @ 29.10.2008, 11:33) *
или в идле.

это чо такое?

Idle - время простоя. В винде в приложение даже специальное сообщение в окно приходит.
Ну а в Qt можно таймером с 0-вым интервалом обойтись. :)

Автор: Fandorin 19.4.2010, 19:25

Прочитал я дисскусию и понял, что дискуссию забросили. Так может быть кто нибудь поделится универсальным методом запуска отдельного потока без зависания GUI. В QT 4.6.2 есть класс Qt::Concurrent, который позволяет запускать произвольную функцию в отдельном потоке. Однако тут есть проблема - число аргументов функции не может быть больше 5. Вот кусок кода, после которого GUI виснет наглухо.

Раскрывающийся текст

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(this->ui->button1, SIGNAL(clicked()), this, SLOT(startThread()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::changeEvent(QEvent *e)
{
    QMainWindow::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void MainWindow::startThread()
{
    QFuture<void> f1 = QtConcurrent::run(mbox);
    f1.waitForFinished();
}

void mbox()
{
    for (int i=0; i < 100000; i++)
    {
        qDebug() << i;
    }
}


Автор: ViGOur 19.4.2010, 19:47

А попробуй данный пример:

"QtConcurrent Progress Dialog Example"
#include <QtGui>

#ifndef QT_NO_CONCURRENT

using namespace QtConcurrent;

const int iterations = 20;

void spin(int &iteration)
{
     const int work = 1000 * 1000 * 40;
     volatile int v = 0;
     for (int j = 0; j < work; ++j)
         ++v;

     qDebug() << "iteration" << iteration << "in thread" << QThread::currentThreadId();
}

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

     // Подготавливаем вектор.
     QVector<int> vector;
     for (int i = 0; i < iterations; ++i)
         vector.append(i);

     // Создаём диалог индикатора выполнения.
     QProgressDialog dialog;
     dialog.setLabelText(QString("Progressing using %1 thread(s)...").arg(QThread::idealThreadCount()));

     // Создаём QFutureWatcher и соединяем сигналы и слоты.
     QFutureWatcher<void> futureWatcher;
     QObject::connect(&futureWatcher, SIGNAL(finished()), &dialog, SLOT(reset()));
     QObject::connect(&dialog, SIGNAL(canceled()), &futureWatcher, SLOT(cancel()));
     QObject::connect(&futureWatcher, SIGNAL(progressRangeChanged(int, int)), &dialog, SLOT(setRange(int, int)));
     QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &dialog, SLOT(setValue(int)));

     // Запускаем вычисление.
     futureWatcher.setFuture(QtConcurrent::map(vector, spin));

     // Отображем диалог и запускаем цикл сообщений.
     dialog.exec();

     futureWatcher.waitForFinished();

     // Запрашиваем future проверить был ли он отменён.
     qDebug() << "Canceled?" << futureWatcher.future().isCanceled();
}

#else

int main()
{
         qDebug() << "Qt Concurrent is not yet supported on this platform";
}

#endif

Автор: Fandorin 19.4.2010, 19:51

Да, спасибо, я видел этот пример. Но допустим мне пока не нужно диалог прогресса. Мне нужно, чтобы просто отвечал интерфейс при выполнении долгого вычисления. Если убрать f1.waitForFinished() GUI отвечает. Однако остается открытый вопрос - что если число параметров равно 6 или более?

Автор: ViGOur 19.4.2010, 20:19

Цитата(Fandorin @ 19.4.2010, 20:51) *
Однако остается открытый вопрос - что если число параметров равно 6 или более?
В таком случае думаю правильней будет создать класс произвольный от QThread и работать уже с ним...

Или как вариант создать структуры, а в ней уже твои параметры. И передавать уже объект структуры.

Автор: Litkevich Yuriy 19.4.2010, 20:29

Цитата(Fandorin @ 19.4.2010, 23:51) *
Если убрать f1.waitForFinished() GUI отвечает.
ну это по моему очевидно, ты остался сидеть в некой функции (в твоём случае MainWindow::startThread), которая выполняется в основном потоке, и ждать завершения доппотока

Автор: Fandorin 19.4.2010, 20:32

QList<QVariant> и его уже передавать :rolleyes: Наш ответ. Теперь параметры - не проблема) Спасибо всем за помощь)

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)