Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > [Qt4] Функция в отдельном потоке


Автор: Girin 20.3.2008, 11:09
Как можно получить значение возвращаемой функцией запущенной в отдельном потоке (использую QThread)  ? 

Автор: SABROG 20.3.2008, 11:35
Унаследуй QThread, переопредели функции, которые должны возвращаться значение. Пример из ассистанта:

Код

         class MyThread : public QThread
         {
         public:
             void run();
         };

         void MyThread::run()
         {
             QTcpSocket socket;
             // connect QTcpSocket's signals somewhere meaningful
             ...
             socket.connectToHost(hostName, portNumber);
             exec();
         }


Например так:

Код

         class MyThread : public QThread
         {
         public:
             void run();
         int retVal;
         };

         void MyThread::run()
         {
         //тут пишется код, который будет выполняться в отдельном потоке
             exec();
             retVal = 0; //например возвратим ноль
         }


И проверять это значение, когда придет сигнал finished. Может быть можно и как-то эстетичнее, сейчас в голову ничего не приходит.

Автор: Lazin 20.3.2008, 11:43
добавь к классу-потоку - переменную, в которую записывай результат работы...

но прежде чем оттуда читать - жди пока поток отработает

хотя мне такой дизайн не нравиться, я свои программы строю по другому)))

Добавлено через 6 минут и 17 секунд
Код

class myThread : public QThread
{
int res_;
HANDLE evt_;
public:
    void run() {
        //do things
        res_ = ....
        SetEvent(evt_);
    }

    int get_result()
    {
        WaitForSingleObject(evt_, INFINITE);//ждем пока поток отработае
        return res_;
    }
};


в коде использовал win32 api, так как не знаю, что там в Qt за синхронизация)))
еще не написал конструктор, потому-что лень...

Добавлено через 8 минут и 42 секунды
дурость конечно смешивать winapi и Qt код))

Автор: SABROG 20.3.2008, 11:54
А какой смысл замораживать приложение в ожидании результирующего значения, зачем тогда поток нужен, если его цель сделать программу рабочей в момент долгих операций ?

Автор: Lazin 20.3.2008, 12:28
ну я же написал что:
Цитата(Lazin @  20.3.2008,  11:43 Найти цитируемый пост)
хотя мне такой дизайн не нравиться, я свои программы строю по другому)))

во вторых:
если нужно прочитать и использовать результат, то нужно полюбому дождаться завершения потока... а в твоем коде можно использовать результат до того как он будет вычислен, результат же не обязательно должен использоваться в слоте получающем сигнал finished (ну и .... этот ваш Qt)

Автор: SABROG 20.3.2008, 12:48
Если есть условие, что что-то должно сделаться в зависимости от результата в потоке, то почему просто не заставить поток это сделать ? Например во всех моих программах, где я использовал чистый WinApi с потоками основная идея сводилась к тому, чтобы по результату потока поменять что-то в интерфейсе программы - переименовать кнопку, включи/отключить кнопки, вывести текст в edit и т.д. Все это я делал из потока, а не из главного цикла.

Если поток должен вернуть массив данных, то почему просто не передать в него указатель на этот массив, он сам его заполнит. Если без результата из потока невозможно дальнейшее выполнение программы, то обычно создают модальное окно с каким-нибудь progressBarом и кнопкой Cancel. В этом случае само наличие потока нужно только для обеспечения комфортности пользователя, мало ли подумает программа зависла, а так видит окошко перерисовывается, кнопочку можно нажать в любой момент, тормозов как с processAllEvents нету.

Автор: Girin 20.3.2008, 14:29
Цитата(SABROG @ 20.3.2008,  11:35)
Унаследуй QThread, переопредели функции, которые должны возвращаться значение. Пример из ассистанта:
.........
И проверять это значение, когда придет сигнал finished. Может быть можно и как-то эстетичнее, сейчас в голову ничего не приходит.

Сделал как вы посоветовали , а именно создал класс производный от QThread , переопределил его метод
Код
void DllThread::run()
{
    ///-------Сбор информации  о версии dll ------
    int ApplicationVersion[4] = {0,0,0,0}; // массив с информацией о версии
    const wchar_t * temp=fileName.toStdWString().c_str();
    if(!getFileVersionInfo(temp,ApplicationVersion))//функция на WinAPI
    {
        QMessageBox::information(NULL,"Result","false") ;
        emit finished();
    }
    char str[32];
    sprintf(str,"version %d.%d.%d.%d",ApplicationVersion[0],ApplicationVersion[1],ApplicationVersion[2],ApplicationVersion[3]);
    fileVersion=QString::fromLocal8Bit(str);//поле, которое используется вместо возвращаемого значения
    exec();
}

Далее объявил одно из приватных полей основного класса как поле типа DllThread, и в конструкторе вызвал соостствующий connect. Но сигнал finished() почему то не генерируется и результата вычислений нет ..   Плюс к этому пришлось перенести определение всех методов основного класса(виджет), которые нужно выполнить  в отдельном потоке в класс, унаследованный от QThread. В итоге код стал малочитаемым и запутанным . Есть ли другой подход

Автор: SABROG 20.3.2008, 14:43
Есть. Определения никуда не переносить, а прописать френда в класс основного окна. Или передать в конструктор тупо указатель, главное, чтобы окно не деструктнулось перед тем как поток завершится.

Самому отправлять finished() не нужно. Оно приходит, когда поток завершается, само.

Автор: Girin 20.3.2008, 14:55
Попробовал вариант с передачей указателя в конструктор, получилось как надо. SABROG, Lazin благодарю за помощь

Автор: SABROG 20.3.2008, 15:34
Кстати глянь еще QtConcurrent, там какая-то крутая технология распараллеливания потоков по ядрам процессора используется.  smile Помимо этого можно тупо передать функцию которая должна выполняться в потоке, без наследования QThread.

Код

QFutureWatcher *watcher  = new QFutureWatcher();
QObject::connect(watcher, SIGNAL(resultReady(const QVariant&)), myObject, SLOT(handleResult(const QVariant &)));

QString foo();
QFuture<QString> f = QtConcurrent::run(foo);
watcher->setFuture(f);

Автор: Girin 22.3.2008, 01:59
Да судя по описанию на офф сайте многообещающая технология , но как я понял только в бета разработке и включена в Qt , начиная с версии 4.4 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)