【问题标题】:QTimer running in QThreadQTimer 在 QThread 中运行
【发布时间】:2021-01-08 23:41:27
【问题描述】:

我需要一个带有计时器的类,它每 100 毫秒执行一次任务,这个类需要在线程中运行,所以我想将 qtimer 与 qthread 结合起来。

我创建了以下代码:

class Worker : public QObject
{
    Q_OBJECT
    public:
    void setEnabled(bool enable);
    
    public slots:
    void initialize();
    
    private:
    void doWork();
    
    QTimer *m_timer;
}

void Worker::initialize()
{
    m_timer = new QTimer(this);
    connect(m_timer, &QTimer::timeout, this, &Worker::doWork, Qt::DirectConnection);
    m_timer->start(100);
}

void Worker::setEnabled(bool enable)
{
    if(enable)
        m_timer->start(100);
    else
        m_timer->stop();
}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc,argv);

    QThread *thread = new QThread;
    Worker *worker = new Worker;
    
    QObject::connect(thread, &QThread::started, worker, &Worker::initialize);
    
    worker->moveToThread(thread);
    thread->start();
    
    app.exec();

    delete worker;
    delete thread;
}

使用以下命令我可以启用/禁用时间

worker->setEnabled(false); worker->setEnabled(true);

我已经测试过,它工作正常,但我想知道这是否正确?

感谢您的帮助

【问题讨论】:

  • 我觉得很好。
  • @JarMan 我看到几个错误(可能是由于没有提供minimal reproducible example),我没有看到任何 QXApplication,同步调用 setEnabled 会导致分段错误,因为 m_timer 的内存直到之后才分离在您的代码中调用显然不知道的初始化,从主线程调用属于新线程的对象,内存泄漏等。
  • 好的,我只是快速浏览一下,因为 OP 说“它工作正常”。
  • QThread *thread = new QThread; Worker *worker = new Worker; - 您正在泄漏这些对象。
  • 你是对的,worker->setEnabled(false) & worker->setEnabled(true) 不能在代码块内。如果这是禁用/启用计时器的正确方法,那更是一个问题。我已经编辑了代码

标签: c++ qt qthread qtimer


【解决方案1】:

不,这并不完全正确。

Worker::setEnabled(bool enable) 也应该是一个插槽,因为它直接调用了QTimer::start() 插槽。直接从主线程调用Worker::setEnabled 会导致未定义的行为。您必须使用信号槽连接从主线程安全地调用 setEnabled

您还应该在构造函数中初始化Worker::m_timer,而不是将其推迟到initialize(),因此如果Worker::setEnabled 的调用早于预期,您就不会遇到悬空指针。 moveToThread 将移动 Worker 的所有孩子,所以这是非常理智的行为。

【讨论】:

    【解决方案2】:

    我唯一需要提的是,m_timer 不能在构造函数中初始化。请参阅此处来自 qt 的信息:

    顺便说一句,这里要注意的一件非常重要的事情是,你永远不应该在 QObject 类的构造函数中分配堆对象(使用 new),因为这个分配是在主线程上执行的,而不是在新的 QThread 实例,这意味着新创建的对象然后由主线程拥有,而不是 QThread 实例。这将使您的代码无法工作。而是在主函数槽中分配此类资源,例如在这种情况下的 initialize(),因为当调用该对象时,对象将位于新线程实例上,因此它将拥有该资源。

    【讨论】:

    • 这仅适用于在没有父级的情况下创建的QObject。在这种情况下,当指定父级时,线程亲和性会在移动时跟随父级。
    猜你喜欢
    • 2012-05-16
    • 2019-02-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-12
    • 1970-01-01
    • 2018-06-27
    • 2017-01-01
    • 2012-06-03
    相关资源
    最近更新 更多