【问题标题】:Running a separate process or thread in Qt在 Qt 中运行单独的进程或线程
【发布时间】:2009-05-28 22:10:59
【问题描述】:

我正在编写我的第一个真正有用的软件。其中一部分将涉及用户查看图像,并选择接受或拒绝它。这样做会导致图像被保存到接受或拒绝的文件夹中,并且可能会旋转和/或调整大小。

目前,我的旋转/调整大小/保存操作正在暂停执行我的程序,但我希望它在后台发生,以便立即显示下一张图像。

是在 Qt 中执行此操作以在单独的线程中处理图像的唯一方法,还是有其他方法?我还在研究 C++ 和 Qt,所以我不想因为潜入一个新领域而迷惑自己!

【问题讨论】:

  • 一句警告。您不能在 GUI 线程之外使用 QPixmap。我最近被这个类似线程图像渲染类型的应用程序咬住了。请改用 QImage。如果你真的需要一个 QPixmap(我确实需要),你必须从线程返回一个 QImage 并在主 GUI 线程中进行转换(这非常昂贵)。

标签: c++ multithreading qt concurrency


【解决方案1】:

Qt 有线程支持。您可能会觉得 this example application 很有趣,因为它与您所描述的有些相似。

另外,here is the full Qt thread documentation

【讨论】:

  • 那么你会建议只潜入并学习基础知识吗?
  • 线程是正确的答案,Qt 的线程支持非常好。如果是我,我只会以身作则。链接应用程序的相似之处在于它在后台执行任务,并允许您在完成时收到通知。举一个有趣或适用于您的示例,然后自己尝试一下。在整个过程更加清晰之前,在文档中查找您不了解的内容。通常这会让你到达你需要去的地方。
  • 当心,示例中存在内存泄漏!线程对象永远不会被删除。为什么他们保护 m_abort 的写操作而不是读操作?!为什么要保护它呢,最糟糕的事情是处理了一个额外的循环。
  • 你的两个链接现在都失效了...
【解决方案2】:

这类任务非常适合线程。不过,您应该首先执行一个“正常”函数来执行此操作,然后在它工作时添加一个读取队列并调用相同处理函数的线程。

Qt 有很多工具可以在这方面为您提供帮助,主要是大多数容器都是线程安全的,还有一些线程算法(如 map-reduce)。还是先同步试试吧。

【讨论】:

    【解决方案3】:

    已编辑

    抱歉,我很难将“排队的自定义类型示例”与需求联系起来。

    据我从问题中可以看出,一旦用户接受或拒绝了图像,它必须是可选的旋转和/或缩放,并且始终保存到特定目录并继续下一个图像。 (-> 不再与用户交互)
    即使用户离开当前对话框,图像仍然必须保存。

    “队列自定义类型示例”只处理一个图像,始终链接到 gui,当用户退出对话框时,线程操作停止。
    因此,如果他从 Queued 示例开始他的程序,他可能会开始编写一个受互斥锁保护的图像队列,以便在有待处理的保存操作时将新图像添加到列表中。否则,用户仍需等待挂起的操作。
    第二个问题是他可能不想在对话框关闭时等待挂起的保存操作。

    为了满足要求,我会做的是使用线程池。为线程池提供所需的保存操作,如果还需要旋转/缩放,则使用基于 QRunnable 的装饰器模式。所有排队都由库正确处理,即使用户离开当前对话框,也会执行挂起的操作。 最后,我可能会使用 Queued 示例代码来加载新图像并为用户提供加载操作的等待指示。

    我的 runnables 和装饰器可能看起来像这样......(可能是一些额外的构造函数来替换 set 函数)所以我可以很容易地添加像这样的新操作 QThreadPool::globalInstance()->start(saver ); 而无需使用任何低级同步对象。

    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 );
    

    【讨论】:

    • 只有一个问题,你为什么使用 boost::shared_ptr?为此目的,有 Qt 特定的类,如 QSharedData、QSharedDataPointer。
    【解决方案4】:

    要么使用QThread 创建一个单独的线程,要么使用带有QRunnable 的线程池工作线程,或者查看高级QtConcurrent 类。 Here 是图像缩放的示例。

    【讨论】:

      【解决方案5】:

      最简单的方法是使用 QtConcurrent::run

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-05-13
        • 2015-05-20
        • 1970-01-01
        • 1970-01-01
        • 2013-09-26
        • 2019-08-12
        • 2020-04-19
        • 2014-09-23
        相关资源
        最近更新 更多