了解 qthread 子类的运行方法和线程上下文

Posted

技术标签:

【中文标题】了解 qthread 子类的运行方法和线程上下文【英文标题】:understanding a qthread subclass's run method and thread context 【发布时间】:2011-03-09 13:40:20 【问题描述】:

我有一个包含很多方法的编码器类。这是 Qthread 的子类。我是多线程的新手,并且

试图了解这个类是如何 线程化它的方法

...我理解线程必须在 qthread 的子类中的方法。并且 this 的运行实现了这个类的线程代码。并且线程仅在调用此类对象的 start 方法时才启动。

问题:首先你推断什么 从这个运行实现

void Encoder::run(void)

    VERBOSE(VB_DEBUG, "Encoder::run");

    if (WILL_PRINT(VB_DEBUG))
        print_stats_timer_id = QObject::startTimer(kEncoderDebugInterval);
    health_check_timer_id = QObject::startTimer(kEncoderHealthCheckInterval);

    if (init())
        exec();
    else
        VERBOSE(VB_ERROR, "Encoder::run -- failed to initialize encoder");

    QObject::killTimer(health_check_timer_id);
    if (print_stats_timer_id)
        QObject::killTimer(print_stats_timer_id);

    cleanup();

问题:线程上下文是什么意思 与其方法的关系。

还有

问题:如果使用这个方法会发生什么 类在这个类之前被调用 线程已经开始

【问题讨论】:

如果可以根据上述帖子中提出的问题提供答案而不是链接到某些博客帖子,那将非常有帮助... 【参考方案1】:

    您编写的类创建了一个线程并初始化了一个 QObject::timer。然后它继续调用用户定义的 init() 函数,然后调用 QThread::exec() 函数。

      我的猜测是,您希望 exec() 是一个用户定义的函数,实际工作将在其中发生。请注意,QThread::exec() 处理线程的 Qt 事件队列。 此外,在某些平台上,您可能会收到“从线程创建计时器时出错”警告消息。当代码在 Linux 上正常执行时,我在 Windows 上遇到了这个错误 另外,请注意,如果您不在线程内调用 QThread::exec() 函数或 QApplication::processEvents(),您的计时器将永远不会发生。

    Qt 中的线程上下文与任何其他线程概念相同。也就是说,所有内存都在线程代码之间共享(此时在“run()”函数中输入)。以及任何其他调用您的对象的上下文。如果此对象可能曾经在线程中执行并从线程外部访问,您必须保护共享数据。

    因为所有数据都在线程上下文之间共享(它是共享内存多处理模型),所以在线程执行之前/之后/期间调用函数没有问题。鉴于:
      在调用任何方法之前,对象已完全构造。除非对象是在线程中创建的,否则这对线程来说不一定是特殊的。 任何数据成员都受到互斥锁的保护(我在#2 中避开了这一点)。 QMutexLocker 是一种方便的基于堆栈的 RAII 方法,用于处理 Qt 中的互斥锁。

我相信我在这里已经完全回答了你的问题,所以我会继续链接到我在另一个网站上写的 RAII 和 threading 文章,以供进一步参考。

编辑:关于线程场景的特殊性:

class MyThreadedClass : public QThread

  MyThreadClass(const boost::shared_ptr<SomeOtherClass> &t_object)
    : m_object(t_object) 

  void doSomething()
  
    // Depending on how this method was called (from main, from internal thread)
    // will determine which thread this runs on, potentially complicating thread
    // safety issues.
    m_object->someThing(); 
  

  void run()
  
    // I'm now in a thread!
    m_object->someFunction(); // oops! The call to someFunction is occurring from 
                              // a thread, this means that SomeOtherClass must be 
                              // threadsafe with mutex guards around shared 
                              // (object level) data.
    // do some other stuff
  
;

int main()

  MyThreadClass thread(someobjectfromsomewhere);
  thread.start(); // MyThreadClass is now running
  thread.doSomething(); // The call to doSomething occurs from main's thread.
                        // This means 2 threads are using "thread", main 
                        // and "thread"'s thread. 
  // The call to thread.doSomething hits Thread.m_object, which means that 
  // now multiple threads are also accessing m_object ("thread" and "main").
  // This can all get very messy very quickly. It's best to tightly control 
  // how many threads are hitting an object, and how

注意:调查QFuture 是个好主意,它旨在处理这种异步任务,如您正在查看的编码器 QFuture 将避免一些潜在的线程问题共享数据和死锁。

【讨论】:

如果我从另一个未在运行中调用或使用的类调用编码器类的方法。这个方法是否会在编码器类上下文中线程化,即使它不存在于运行中。这个方法会被线程化吗? 我将更新我的答案以解决问题的这方面。 很好的例子和解释。我的问题与“thread.doSomething();”有关这个方法是运行在主线程上下文还是 mythread 上下文中。 它发生在主线程中。但重要的是要理解“上下文”在这里是一个棘手的词,因为所有内存都在线程之间共享。

以上是关于了解 qthread 子类的运行方法和线程上下文的主要内容,如果未能解决你的问题,请参考以下文章

QT多线程操作

qt中通过重写run方法创建线程与通过movetothread方法有啥区别

Qt:将事件发布到 QThread 的正确方法?

Qt如何循环创建线程

如何在多线程中将指针传递给子类 Qthread

从 QThread 启动 QProcess [重复]