C++ Qt中多线程的工作类

C++ Qt中多线程的工作类,c++,multithreading,qt,worker-thread,C++,Multithreading,Qt,Worker Thread,我一直在考虑可以用于并行计算的工人类 我希望避免在创建对象后必须将辅助线程显式移动到单独线程的情况,即: Worker worker; QThread thread; worker.moveToThread(&thread); thread.start(); worker.start(); 这就是我提出的解决方案: 标题: #include <QObject> #include <QThread> class ThreadedWorker : public Q

我一直在考虑可以用于并行计算的工人类

我希望避免在创建对象后必须将辅助线程显式移动到单独线程的情况,即:

Worker worker;
QThread thread;
worker.moveToThread(&thread);
thread.start();
worker.start();
这就是我提出的解决方案:

标题:

#include <QObject>
#include <QThread>

class ThreadedWorker : public QObject
{
    Q_OBJECT
public:
    explicit ThreadedWorker(QObject *parent = 0);
signals:
    void finished(ThreadedWorker* worker);
public slots:
    void start();
protected:
    virtual void run();
    QThread workerThread_;
    bool isRunning_;
};
在Zailborg发表评论后更新:

所以现在我只是创建:

ThreadedWorker worker1;
ThreadedWorker worker2;
通过一些外部信号调用它们的
start()
插槽,它们并行运行

但是,我主要关心的是,将
QThread workerThread\uuuz
作为
ThreadedWorker
类的成员并将对象移动到构造函数中的该线程是否是一种不好的做法。

请看一下:

除了我的评论之外,我认为在堆栈上分配一个对象并将其移动到另一个线程是不可取的

将QThread workerThread_uu作为ThreadedWorker类的成员是否是一种不好的做法

当对象移动到其线程时,对象及其子对象将被移动。当您将父对象传递给QObject派生类的构造函数或调用setParent时,子对象是Qt父子层次结构中链接的对象

对于成员指针,例如QThread指针,它不是类的“子级”。因此,当ThreadedWorker对象移动到新线程时,这将起作用。但是,由于混淆了线程关联性,可能会出现问题。主对象被移动到新线程,但保留一个指向线程关联性不同的对象的成员指针;QThread*指向的对象

问题中给出的代码不是指QThread指针,而是指QThread实例。考虑到这一点,考虑文档的状态:-< /P> 警告:此函数不是线程安全的;当前线程必须与当前线程关联相同。换句话说,此函数只能将对象从当前线程“推”到另一个线程,不能将对象从任意线程“拉”到当前线程

因此,我怀疑QThread和QObject::moveToThread的设计期望QThread的亲和性是稳定的,不会被改变。作为被移动对象的成员,情况就不会是这样了

出于这个原因,我认为将QThread实例作为QObject的成员并将该对象移动到该线程不是一个好主意

如果您打算使用QThread,那么我建议您阅读并遵循中概述的方法


此外,moveToThread的功能允许QThread与QObject的1对多关系,因此创建一个QThread对象并将多个QObject实例移动到新线程是完全可以接受的。另外,创建比可用处理器内核更多的线程通常没有什么好处。

对于任何感兴趣的人来说,一个小助手类允许创建具有自动可变参数推断的工作线程。请注意,C++17是必需的(也就是说,不需要指定模板参数)。有关完整的源代码,请参阅:

worker.hpp

#ifndef QT5_UI_WORKER_HPP
#define QT5_UI_WORKER_HPP

#include <QObject>
#include <QString>
#include <functional>
#include <tuple>

namespace ui
{
    class worker_object :
            public QObject
    {
    Q_OBJECT

    public:
        inline worker_object() = default;
        inline ~worker_object() = default;

    public slots:
        inline virtual void run() { /*...*/ };

    signals:
        void finished();
        void error(const QString& err_msg);
    };

    namespace helper
    {
        template <int... Is>
        struct index {};

        template <int N, int... Is>
        struct gen_seq : gen_seq<N - 1, N - 1, Is...> {};

        template <int... Is>
        struct gen_seq<0, Is...> : index<Is...> {};
    }

    template<typename... Ts>
    class worker :
            public worker_object
    {
    public: /* Functions */
        template<typename Func, typename... Args>
        inline worker(Func&& fn, Args&& ... args) :
                fn_(std::forward<Func>(fn)),
                args_(std::forward<Args>(args)...)
        { /*...*/ }

        inline ~worker() = default;

        inline void run() override
        {
            func(args_);
            emit finished();
        }

    private: /* Functions */
        template<typename... Args, int... Is>
        inline void func(std::tuple<Args...>& tup, helper::index<Is...>)
        {
            fn_(std::get<Is>(tup)...);
        }

        template<typename... Args>
        inline void func(std::tuple<Args...>& tup)
        {
            func(tup, helper::gen_seq<static_cast<int>(sizeof...(Args))>{});
        }

    private: /* Class members */
        std::function<void(Ts...)> fn_;
        std::tuple<Ts...> args_;
    };

    /**
     * @brief Helper function to create a worker by which specification of the template arguments aren't necessary.
     */
    template<typename Func, typename... Args>
    worker<Args...> make_worker(Func&& fn, Args&& ... args)
    {
        return worker<Args...>(std::forward<Func>(fn), std::forward<Args>(args)...);
    }
}

#endif
    void main_window::start_worker(worker_object *thread_worker, const worker_callback& on_finish,
                                   const worker_error_callback& on_error)
    {
        auto *worker_thread = new QThread;
        thread_worker->moveToThread(worker_thread);
        connect(thread_worker, &worker_object::error, this, on_error);
        connect(worker_thread, &QThread::started, thread_worker, &worker_object::run);
        connect(thread_worker, &worker_object::finished, worker_thread, &QThread::quit);
        connect(thread_worker, &worker_object::finished, this, on_finish);
        connect(thread_worker, &worker_object::finished, thread_worker, &worker_object::deleteLater);
        connect(worker_thread, &QThread::finished, worker_thread, &QThread::deleteLater);
        worker_thread->start();
    }
main\u window.cpp示例1:无参数

void main_window::service_example()
{
    //STEP 1: specify a (synchronous) task for the worker.
    auto *work = new worker(make_worker([this]()
    {
        auto task_len_ms = 2500; //ms
        logger_->info("Doing some concurrent work for " + std::to_string(task_len_ms) + " milliseconds...");
        QThread::msleep((unsigned)task_len_ms);
    }));

    //STEP 2: specify the completion handler. Called upon a worker_object::finished signal.
    auto on_finish_callback = [this]()
    {
        logger_->info("Concurrent work finished!");
    };

    //STEP 3: specify an error handler. Called upon a worker_object::error(const QString&) signal.
    auto on_error_callback = [this](const QString& err_msg)
    {
        logger_->error(err_msg.toStdString());
    };

    //STEP 4: start the worker.
    start_worker(work, on_finish_callback, on_error_callback);
}
//STEP 1: specify a (synchronous) task for the worker.
auto *work = new worker(make_worker([this](const std::string& personal_msg, unsigned long wait_time)
{
    logger_->info(personal_msg);
    QThread::msleep((unsigned)wait_time);
}, "Hello, world?", 2500));

//STEP 2: specify the completion handler. Called upon a worker_object::finished signal.
//STEP 3: specify an error handler. Called upon a worker_object::error(const QString&) signal.
//STEP 4: start the worker.
main\u window.cpp示例2:一些参数

void main_window::service_example()
{
    //STEP 1: specify a (synchronous) task for the worker.
    auto *work = new worker(make_worker([this]()
    {
        auto task_len_ms = 2500; //ms
        logger_->info("Doing some concurrent work for " + std::to_string(task_len_ms) + " milliseconds...");
        QThread::msleep((unsigned)task_len_ms);
    }));

    //STEP 2: specify the completion handler. Called upon a worker_object::finished signal.
    auto on_finish_callback = [this]()
    {
        logger_->info("Concurrent work finished!");
    };

    //STEP 3: specify an error handler. Called upon a worker_object::error(const QString&) signal.
    auto on_error_callback = [this](const QString& err_msg)
    {
        logger_->error(err_msg.toStdString());
    };

    //STEP 4: start the worker.
    start_worker(work, on_finish_callback, on_error_callback);
}
//STEP 1: specify a (synchronous) task for the worker.
auto *work = new worker(make_worker([this](const std::string& personal_msg, unsigned long wait_time)
{
    logger_->info(personal_msg);
    QThread::msleep((unsigned)wait_time);
}, "Hello, world?", 2500));

//STEP 2: specify the completion handler. Called upon a worker_object::finished signal.
//STEP 3: specify an error handler. Called upon a worker_object::error(const QString&) signal.
//STEP 4: start the worker.

为什么不直接使用?你发布的代码不能并发运行。。。您可以从
main线程调用
start
<代码>开始
调用
运行
如果任何
正在运行
。。。因此,基本上您和您的
main线程都在调用应该在中运行的代码parallel@Zailborg你是对的-我的实际代码过于简化了。
start()
插槽在某些外部信号上被调用(此处未显示)。我已经更新了我的问题。非常感谢。这正是我想要的答案!