Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Using Threads without subclassing
Forum Updated to NodeBB v4.3 + New Features

Using Threads without subclassing

Scheduled Pinned Locked Moved General and Desktop
5 Posts 3 Posters 3.4k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    dawu
    wrote on last edited by
    #1

    Hello everybody!

    Some weeks ago I started working with Qt and I am happy with this great framework! Now, I am working at a university-project using Microsoft's Kinect to generate pointclouds/meshes in realtime. In this context I have to work with threads (which is my first time using them) and I have some basic problems.

    I work under Linux Mint 11/Ubuntu 11.04 using Qt Creator 2.1.0, Qt 4.7.2 and the great Kinect-interface libfreenect of the "OpenKinect-project":http://www.openkinect.org.

    I tried a lot and want to follow the "threading-idea" without subclassing, explained at "here":http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/. But it seems I do something wrong or maybe misunderstand the use of threads, why I need help. Also searching the web didn't help.

    "Here":http://dl.dropbox.com/u/643465/klassendiagramm_klein.png is a pseudo-class-diagram showing the important classes and data-flow.

    !http://dl.dropbox.com/u/643465/klassendiagramm_klein.png(Class-Diagram)!

    Basically, there are three QGLWidget subclasses presenting data: RGBWidget (displaying the Kinect's RGB-image), DepthWidget (displaying the Kinect's depth-image) and a MeshWidget (displaying a pointcloud reconstructed from the rgb- and depth-image).

    The ImageController owns a timer, which runs with an interval of 0 msecs. It grabs the RGB- and depth-image of the Kinect and forwards them to the RGBWidget and DepthWidget. And it should forward them to the Reconstructor, which creates a pointcloud and colors (of the points) and forwards them to the MeshWidget. Unfortunately the reconstruction needs some time, why I want to move this operation to a thread.

    I followed "this":http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/ explanation and implemented the ImageController and Reconstructor as follows:

    imagecontroller.h
    @
    #include <QObject>
    #include <QTime>
    #include <QThread>

    #include <vector>

    #include "qkinect.h"
    #include "rgbwidget.h"
    #include "depthwidget.h"
    #include "meshwidget.h"

    #include "reconstructor.h"

    class ImageController : public QObject
    {
    Q_OBJECT
    public:
    explicit ImageController(QObject *parent, RGBWidget *rgbWidget, DepthWidget
    *depthWidget, MeshWidget *meshWidget);

    private:
    QKinect *kinect;

    Reconstructor recon;
    QThread reconThread;

    RGBWidget *rgbWidget;
    DepthWidget *depthWidget;
    MeshWidget *meshWidget;

    QTime timer;

    std::vector<uint8_t> rgbImage;
    std::vector<uint8_t> depthImage;
    std::vector<uint16_t> depthRaw;

    protected:
    void timerEvent(QTimerEvent *event);
    };
    @

    imagecontroller.cpp
    @
    #include "imagecontroller.h"

    ImageController::ImageController(QObject *parent, RGBWidget *rgbWidget, DepthWidget
    *depthWidget, MeshWidget *meshWidget) :
    QObject(parent), recon()
    {
    // Do some init-stuff here

    startTimer(0);

    recon.moveToThread(&reconThread);

    connect(&reconThread, SIGNAL(started()), &(this->recon), SLOT(startReconstruction()));
    connect(&(this->recon), SIGNAL(finished()), &reconThread, SLOT(quit()));

    connect(&(this->recon), SIGNAL(newPoints(std::vector< std::vector<float> >)), this->meshWidget, SLOT(setPoints(std::vector< std::vector<float> >)));
    connect(&(this->recon), SIGNAL(newColors(std::vector< std::vector<int> >)), this->meshWidget, SLOT(setColors(std::vector< std::vector<int> >)));
    }

    void ImageController::timerEvent(QTimerEvent *event)
    {
    if (kinect->getRGBImage(rgbImage))
    {
    rgbWidget->setImage(rgbImage);

    if (!reconThread.isRunning())
    {
    recon.setRgbValues(rgbImage);
    recon.setDepthValues(depthRaw);
    reconThread.start();
    }
    }

    if (kinect->getDepthImage(depthImage))
    {
    depthWidget->setImage(depthImage);
    }

    if (kinect->getDepthRaw(depthRaw))
    {
    if (!reconThread.isRunning())
    {
    recon.setRgbValues(rgbImage);
    recon.setDepthValues(depthRaw);
    reconThread.start();
    }
    }
    }

    @

    reconstructor.h
    @
    #include <QObject>
    #include <QMetaType>
    #include <QDebug>

    #include <vector>
    #include <stdint.h>

    #include "YMLParser.h"

    class Reconstructor : public QObject
    {
    Q_OBJECT
    public:
    explicit Reconstructor(QObject *parent = 0);

    private:
    YMLParser yml;

    std::vector<uint8_t> rgbValues;
    std::vector<uint16_t> depthValues;

    std::vector< std::vector<float> > points;
    std::vector< std::vector<int> > colors;

    signals:
    void newPoints(std::vector< std::vector<float> > points);
    void newColors(std::vector< std::vector<int> > colors);

    void finished();

    public slots:
    void startReconstruction();

    void setRgbValues(std::vector<uint8_t> rgbValues);
    void setDepthValues(std::vector<uint16_t> depthValues);
    };

    #endif // RECONSTRUCTOR_H
    @

    reconstructor.cpp
    @
    #include "reconstructor.h"

    Reconstructor::Reconstructor(QObject *parent) :
    QObject(parent),
    yml("/path/to/calib.yml")
    {
    // Do some init-stuff here

    qRegisterMetaType< std::vector< std::vector<float> > >("std::vector< std::vector<float> >");
    qRegisterMetaType< std::vector< std::vector<int> > >("std::vector< std::vector<int> >");
    }

    void Reconstructor::startReconstruction()
    {
    // Do reconstruction here

    emit newPoints(points);
    emit newColors(colors);

    emit finished();
    }

    void Reconstructor::setRgbValues(std::vector<uint8_t> rgbValues)
    {
    this->rgbValues = rgbValues;
    }

    void Reconstructor::setDepthValues(std::vector<uint16_t> depthValues)
    {
    this->depthValues = depthValues;
    }

    @

    Unfortunately, the performance of my program doesn't get better and it seems that I did something wrong. I have no idea how to go on and would be very thankful for any hint.

    Btw: Most likely, I did some beginner-mistakes independent from the threading-topic. Any suggestion for improvement is welcome!

    Regards,
    Daniel

    1 Reply Last reply
    0
    • V Offline
      V Offline
      vezprog
      wrote on last edited by
      #2

      If you are only using a single QThread and you want events to execute within the QThread itself, you have to start an event loop. Create a class and inherit a QThread, and in the custom protected function run() call exec(). This will allow for your events to be triggered. When you want to exit the event loop, call quit()

      so in your QThread class
      @
      QThreadClassName::run()
      {
      .. // do anything
      .. // do anything
      .. // do anything
      exec(); // start the event loop
      }
      @

      1 Reply Last reply
      0
      • D Offline
        D Offline
        dawu
        wrote on last edited by
        #3

        Hello,

        thanks for your reply. I'll try "QThread-subclassing-approach" tomorrow again. But I wanted to avoid it since I read "The great QThread Mess":http://www.christeck.de/wp/2010/10/23/the-great-qthread-mess/ and "You're doing it wrong":http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/, where the "moveToThread-approach" is explained and recommended. That's why I wanted to implement it.

        I think it's easier and shorter to realize and clearly separates the computation from the thread.

        But I'll give it a try tomorrow.

        Any other suggestions, why my approach not works?

        Regards,
        Daniel

        1 Reply Last reply
        0
        • S Offline
          S Offline
          stima_ua
          wrote on last edited by
          #4

          It's simple illustration how it can be used.

          @
          class Worker : public QObject {
          Q_OBJECT

          public:
          Worker(QObject *parent = 0) : QObject(parent) {}
          ~Worker() {}

          public slots:
          void doSomeWork()
          {
          emit finished();
          emit workResult();
          }
          void doAnotherWork()
          {
          emit finished();
          emit workResult();
          }

          signals:
          void workResult();
          void finished();
          };


          class MyWidget : public QWidget {
          Q_OBJECT

          public:
          MyWidget(QWidget *parent = 0) : QWidget(parent), timerId(-1)
          {
          worker = new Worker; //without parent
          workerThread = new QThread; //you can set parent

          worker->moveToThread(workerThread);
          workerThread->start(); //start eventloop

          timerId = startTimer(/interval/);

          connect(worker, SIGNAL(workResult()), this, SLOT(workResult())); //Qt::QuededConnection
          connect(worker, SIGNAL(finished()), this, SLOT(finished())); //Qt::QuededConnection

          connect(this, SIGNAL(doAnotherWorkr()), worker, SLOT(doAnotherWorkr())); //Q::QuededConnection
          }
          ~MyWidget()
          {
          if (timerId != -1)
          {
          killTimer(timerId);
          timerId = -1;
          }

          workerThread->quit();
          workerThread->wait();

          delete worker;
          delete workerThread;
          }

          public slots:
          void workResult()
          {
          //do something
          }
          void finished()
          {
          //do something
          }

          private:
          Worker *worker;
          QThread *workerThread;

          int timerId;

          void timerEvent(QTimerEvent*)
          {
          if ( someWork )
          {
          //you can
          //1: QMetaObject::invokeMethod(worker, "doAnotherWork"); //for qued
          /2:/ emit doAnotherWorkr(); //for qued
          //3: worker->doAnotherWorkr(); //for direct, or set connection to Qt::DircetConnection end emit signal doAnotherWork();
          }
          }

          signals:
          void doAnotherWorkr();
          };
          @

          1 Reply Last reply
          0
          • D Offline
            D Offline
            dawu
            wrote on last edited by
            #5

            Thank you for your reply, stima_ua.

            It seems that my thread works now, but nevertheless my QGLWidgets "stops" in intervalls. So it seems that the general structure of my program might be wrong... :o(

            Is it generally possible to render multiple QGLWidgets simultaneously/in realtime? Or do I have to use multiple GL-contexts? Or should the Widgets itselfs run in different threads?

            Is it better to let the Widgets fetch the Images or to deliver them from a "ImageContoller", as I did?

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved