Running a separate process or thread in Qt

17,380

Solution 1

Qt has thread support. You might find this example application interesting since it's somewhat similar to what you describe.

Also, here is the full Qt thread documentation.

Solution 2

these kind of tasks are perfectly suited for threads. still, you should first do a 'normal' function that does it, and when it works add a thread that reads a queue and calls the same processing function.

Qt has a lot of tools to help you on this, mainly the fact that most of the containers are thread-safe, and also a couple of threading algorithms (like map-reduce). still, first try it synchronously.

Solution 3

Edited

Sorry guys, I have a very hard time linking the "Queued Custom Type Example" to the requirements.

As far as I can tell from the question, once the user has accepted or rejected the image it must be optional rotated and/or scaled and always saved to a specific directory and go on to the next image. (-> no interaction anymore with the user)
Even if the user leaves the current dialog the image still has to be saved.

The "Queued Custom Type Example" handles only one image, is always linked to the gui and when the users exit the dialog the thread operation is stopped.
So if he starts his program from the Queued example he will probably start writing an mutex protected image queue so he can add new images to the list if there are pending save operations. Otherwise the user still has to wait on pending operations.
The second problem is that he probably doesn't want to wait on pending save operations when the dialog closes.

What I would do to meet the requirements is working with the thread pool. Feed the thread pool the save operations you want and use a decorator pattern based on QRunnable if it also needs to be rotated/scaled. All the queueing is handled correctly by the library and pending operations are executed even if the user leaves the current dialog. At the end I would possibly use the Queued example code to load new images and give the user a wait indication for the loading operation.

My runnables and decorator would probably look like this ... (maybe some additional constructors to replace the set functions) so I can very easly add new operation like this QThreadPool::globalInstance()->start(saver ); without using any low level synchronisation object.

class ImageDecorator : public QRunnable
{
    NextStep nextStep;
public:
    typedef boost::shared_ptr<QRunnable> NextStep;

    ImageDecorator(const NextStep& nextStep) : nextStep(nextStep) {
    }   

    ImageDecorator() : nextStep() {
    }

    // set/get image functions....

protected:
    void next() {
        if( nextStep )
            nextStep->run();
    }
};


class RotateImage : public ImageDecorator
{
public:
    typedef boost::shared_ptr<Image> Image;

    RotateImage(const NextStep& nextStep) : ImageDecorator( nextStep) {
    }   

    RotateImage() : ImageDecorator() {
    }
    // set angle functions....

private:
    void run()
    {
        // rotate the image
        // ...
        next();
    }
};

class ResizeImage : public ImageDecorator
{
public:
    typedef boost::shared_ptr<Image> Image;

    ResizeImage(const NextStep& nextStep) : ImageDecorator( nextStep) {
    }   

    ResizeImage() : ImageDecorator() {
    }
    // set size functions....

private:
    void run()
    {
        // resize the image
        next();
    }
};

class SaveImage : public ImageDecorator
{
public:
    typedef boost::shared_ptr<Image> Image;

    SaveImage(const NextStep& nextStep) : ImageDecorator(nextStep) {
    }   

    SaveImage() : ImageDecorator() {
    }
   // set fileName functions....

private:
    void run()
    {
        // save the image
        next();
    }
};

// save the image 
SaveImage *const saver( new SaveImage() );
saver->setImage( /*use shared pointer*/ );
saver->setFilename( ... );

QThreadPool::globalInstance()->start( saver );

// rotate and save the image 
const ImageDecorator::NextStep saver( new SaveImage() );
saver->setImage( /*use shared pointer*/ );
saver->setFilename( ... );
RotateImage *const rotateAndSave( new RotateImage( saver ) );
rotateAndSave->setImage( /*use shared pointer*/ );
rotateAndSave->setAngle( ... );

QThreadPool::globalInstance()->start( rotateAndSave );


// resize rotate  and  save the image 
const ImageDecorator::NextStep saver( new SaveImage() );
saver->setImage( /*use shared pointer*/ );
saver->setFilename( ... );
const ImageDecorator::NextStep rotateAndSave( new RotateImage( saver ) );
rotateAndSave->setImage(/*use shared pointer*/ );
rotateAndSave->setAngle( ... );
ResizeImage *const resizeRotateAndSave( new ResizeImage( rotateAndSave ) );
resizeRotateAndSave->setImage( /*use shared pointer*/ );
resizeRotateAndSave->setSize( ... );

QThreadPool::globalInstance()->start( resizeRotateAndSave );

Solution 4

Simplest way to do that is to use QtConcurrent::run

Solution 5

Either create a separate thread with QThread or use threadpool worker threads with QRunnableor take a look at high level QtConcurrent class. Here is an example for image scaling.

Share:
17,380
Skilldrick
Author by

Skilldrick

I started working at Twitter in November 2011. Loving it so far :) I've got a blog at http://skilldrick.co.uk where I talk about programming (mostly JavaScript and Ruby at the moment). Blog Twitter LinkedIn Stack Overflow Careers CV

Updated on July 29, 2022

Comments

  • Skilldrick
    Skilldrick almost 2 years

    I'm writing my first proper useful piece of software. Part of it will involve the user viewing an image, and choosing to accept or reject it. Doing this will cause the image to be saved to an accepted or rejected folder, and possibly rotated and/or resized.

    At the moment, my rotate/resize/save operation is pausing execution of my program, but I'd like it to happen in the background so the next image is displayed instantly.

    Is the only way to do this in Qt to process the image in a separate thread, or is there another way? I'm still getting my head round C++ and Qt, so I don't want to confuse myself by diving into a new field!