C++ QThread与std::thread

C++ QThread与std::thread,c++,multithreading,qt,std,qthread,C++,Multithreading,Qt,Std,Qthread,我在“pthread vs std::thread”和“QThread vs pthread”上看到了不同的主题,但在“std::thread vs QThread”上没有看到任何主题 我必须编写一个软件来驱动3D打印机,并且需要使用线程。将有一个线程不断检查安全性,另一个线程执行打印过程,一些线程分别驱动每个硬件组件(移动、喷射等)。。。 该程序是用C++11/Qt为Windows开发的 首先,我想使用QThread,但在我看来,QThread不允许您像std::thread那样做很多事情,例

我在“pthread vs std::thread”和“QThread vs pthread”上看到了不同的主题,但在“std::thread vs QThread”上没有看到任何主题

我必须编写一个软件来驱动3D打印机,并且需要使用线程。将有一个线程不断检查安全性,另一个线程执行打印过程,一些线程分别驱动每个硬件组件(移动、喷射等)。。。 该程序是用C++11/Qt为Windows开发的

首先,我想使用QThread,但在我看来,QThread不允许您像std::thread那样做很多事情,例如,在阅读Anthony Williams的“C++并发操作”时,我发现,通过执行类似于
std::threadt1(&Class::function,this,…)的操作,可以让std::thread从另一个线程执行函数这似乎不可能与QThread一起使用

我最希望使用的机制是一种表示我希望在当前线程或另一个线程中执行函数的方式。


您会选择哪一个执行此操作?为什么?

QThread
如果您想将线程集成到Qt系统中(比如必须发出信号或连接到某些插槽),那么它很好

<>虽然代码的布局> QTox仍然是这样,所以它与“旧”C++一起工作。为了在线程中运行,您必须创建一个类和所有这些开销(代码和键入)

如果您只是想启动一个线程,我认为c++11
std::thread
就不那么冗长了。您可以只使用lambda或函数指针,并且可以根据需要提供任意多的参数。因此,对于简单线程,我建议使用c++11线程而不是QThreads

当然,这可能是一个意见的问题,你更喜欢哪一个


虽然Qt有几个不同的高级线程对象,但C++没有。如果你需要其中的一些而不是基本线程,或者你根本不需要基本线程,但是这些更适合你,那么你可能想研究一下

就像一个
QThreadPool
,或者如果你需要等待的话,简单地说就是一个。是关于Qt中裸线程的替代方案的一些说明


QConcurrent
也更接近于c++11
future
async
,例如,它还可以在可选的线程池中运行

QThread
不仅仅是一个线程,它还是一个线程管理器。如果你想让你的线程玩Qt,那么
QThread
就是最好的选择。Qt是事件驱动的,就像大多数现代编程一样。这比“让线程运行函数”更复杂、更灵活

在Qt中,您通常会创建一个worker和一个
QThread
,将worker移动到该线程,然后事件系统为该worker对象调用的每个函数都将在worker对象与之关联的线程中执行

因此,您可以将您的功能封装在不同的worker对象中,例如
SafetyChecker
Printer
ServoDriver
JetDriver
等等,创建每个对象的实例,将其移动到专用线程,然后设置。您仍然可以调用将“阻塞”的函数,而不是使用细粒度事件,并使用原子或互斥来执行线程间同步。只要不阻塞main/gui线程,就没有问题

您可能不希望执行打印机代码事件驱动,因为在涉及排队连接的多线程场景中,排队连接比直接连接甚至虚拟调度稍微慢一些。如此之多,以至于如果您将多线程处理变得过于细粒度,您很可能会实际体验到巨大的性能损失

这就是说,使用Qt的非gui功能有其自身的优点,它可以让您更容易地进行更干净、更灵活的设计,并且如果您正确地实现这些功能,您仍然可以获得多线程的好处。您仍然可以使用事件驱动的方法来管理整个过程,这将比仅使用
std::thread
要简单得多,后者是一种级别更低的构造。您可以使用事件驱动的方法来设置、配置、监视和管理设计,而关键部分可以在辅助线程中的阻塞函数中执行,以尽可能低的同步开销实现细粒度控制


澄清一下——答案并不关注异步任务的执行,因为其他两个答案已经在做了,而且正如我在评论中提到的,异步任务并不是真正用于控制应用程序的。它们适合于执行小任务,这些任务仍然需要比您想要阻止主线程花费更多的时间。作为推荐的指导原则,所有需要25毫秒以上时间的操作最好异步执行。然而,打印可能需要几分钟甚至几小时的时间,这意味着连续运行控制功能,并行运行并使用同步。异步任务不会为控制应用程序提供性能、延迟和顺序保证。

std::thread
QThread
的主要问题是它按照tin上的说明执行:为您创建一个线程,一个可能只做一件事的线程。使用
std::thread
同时运行函数是非常浪费的:线程是昂贵的资源,因此创建一个函数只是为了运行某些函数通常是过分的

虽然std::thread t1(&Class::function,this,…)看起来不错,但这通常是一种过早的悲观主义,将其作为“同时做事情”的通用方法是错误的。你可以做得更好

  • 如果要在工作线程中并发运行函数/functor/方法,请使用
    QtConcurrent::run
    std::async

    QtConcurrent::run
    使用
    // interface
    QThreadPool * ioPool();
    
    // implementation
    Q_GLOBAL_STATIC(QThreadPool, ioPool_impl);
    QThreadPool * ioPool() { return ioPool_impl; }
    
    class MyWidget : public QWidget {
      QLabel m_label;
      ...
      Q_SIGNAL void setImage(const QImage &);
     public:
      MyWidget() {
       ...
       connect(MyWidget, &MyWidget::setImage, this, [this](const QImage & image){
        m_label.setPixmap(QPixmap::fromImage(image));
       });
       QtConcurrent::run(ioPool(), [this]{ setImage({"/path/to/image.png"});  });
      }
    };