Ele*_*une 11 c++ qt multithreading std qthread
我在"pthread vs std :: thread"和"QThread vs pthread"上看到了不同的主题,但在"std :: thread vs QThread"中没有.
我必须编写一个软件来驱动3D打印机并需要使用线程.将有一个线程将不断检查安全性,另一个用于执行打印过程,一些用于分别驱动每个硬件组件(运动,喷射......)等等...该程序是用Windows开发的C++ 11/QT.
首先我想使用QThread,但在我看来,QThread不允许你像std :: thread那样做很多东西,例如,在阅读Anthony Williams的"C++ Concurrency in Action"时,我看到它是可能的要求std :: thread通过执行类似于std::thread t1(&Class::function, this, ...);QThread似乎无法执行的操作从另一个线程执行函数.
我想拥有的机制是一种说法,如果我想在当前线程或另一个线程中执行一个函数.
您会选择哪一个以及为什么?
dte*_*ech 14
QThread它不仅仅是一个线程,它也是一个线程管理器.如果你想让你的线程玩Qt,那么QThread就是要走的路.Qt是事件驱动的,就像大多数现代编程一样.这比"让一个线程运行一个函数"更复杂和灵活.
在Qt中,您通常与a一起创建一个worker QThread,将worker移动到该线程,然后由该事件系统为该worker对象调用的每个函数将在该worker对象具有亲和力的线程中执行.
所以,你可以封装在不同的工人对象的功能,也就是说SafetyChecker,Printer,ServoDriver,JetDriver等,每个创建的实例,将其移动到一个专用的线程,你设置.您仍然可以调用"阻塞"而不是使用细粒度事件的函数,并使用原子或互斥来进行线程间同步.这没有什么不妥,只要你不阻止main/gui线程.
您可能不希望执行打印机代码事件驱动,因为在多线程方案中涉及排队连接,这比直接连接或甚至虚拟分派稍慢.这么多,如果你让你的多线程太精细,你实际上可能会遇到巨大的性能损失.
话虽如此,使用Qt的非gui东西有其自身的优点,它将使您更容易制作更清晰,更灵活的设计,如果您正确实施,您仍将获得多线程的好处.您仍然可以使用事件驱动的方法来管理整个事情,它将比仅使用更容易std::thread,这是一个更低级别的构造.您可以使用事件驱动方法来设置,配置,监视和管理设计,而关键部分可以在辅助线程中的阻塞功能中执行,以便以尽可能低的同步开销实现细粒度控制.
澄清一下 - 答案并不关注异步任务执行,因为其他两个答案已经完成,因为正如我在评论中提到的那样,异步任务并不是真正用于控制应用程序.它们适合执行小任务,这仍然需要比你想要阻止主线程更多的时间.作为推荐的指导原则,超过25毫秒的所有内容最好不要执行异步.而打印可能需要几分钟甚至几小时,并且意味着连续运行控制功能,并行和使用同步.异步任务不会为您提供控制应用程序的性能,延迟和顺序保证.
主要的问题std::thread,并QThread为它做什么它在锡说:为您创建一个线程,线程可能会做的只有一件事."并发"使用函数std::thread是非常浪费的:线程是昂贵的资源,因此创建一个只是为了运行某些函数通常是过度的.
虽然std::thread t1(&Class::function, this, ...)看起来很好,但通常是过早的悲观,并建议它作为"同时做事"的一些普遍方式是恕我直言错误.你可以做得更好.
如果要在工作线程中同时运行函数/函数/方法,请使用QtConcurrent::run或std::async.
QtConcurrent::run默认情况下使用默认线程池,您也可以传递自己的实例QThreadPool.典型的情况是将默认线程池用于CPU绑定任务,例如计算,图像转换,渲染等,并使用专用的,更大的I/O线程池来执行由于受限制而阻塞的操作.您被迫使用的API(例如,许多数据库库仅提供阻止API,因为它们的设计从根本上被破坏).例:
// interface
QThreadPool * ioPool();
// implementation
Q_GLOBAL_STATIC(QThreadPool, ioPool_impl);
QThreadPool * ioPool() { return ioPool_impl; }
Run Code Online (Sandbox Code Playgroud)如果你想QObject在另一个线程中生活(可能与其他对象共存),请使用QThread然后将对象移动到该线程moveToThread.
从工作线程发出信号以将数据线程安全地传递给主线程是一种习惯用法.例如,假设您想要一个响应式GUI并希望在工作线程中从磁盘加载图像:
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"}); });
}
};
Run Code Online (Sandbox Code Playgroud)QThread 如果你想将线程集成到Qt系统中(比如必须发出信号或连接到某些插槽),这很好
虽然布局QThread仍然是,所以它适用于"旧"c ++.你必须创建一个类,所有这些开销(代码和打字明智)只是为了在一个线程中运行.
如果你只是想创建一个线程我认为c ++ 11 std::thread不那么冗长/代码你必须编写.您可以使用lambda或函数指针,并可以根据需要提供尽可能多的参数.因此,对于简单的线程,我建议在QThreads上使用c ++ 11线程.
当然,你可能更喜欢那些人.
虽然Qt有几个不同的高级线程对象,但C++却没有.如果您需要其中一些而不是基本线程,或者您根本不需要基本线程,那么您可能需要查看这些,但这些更适合您.
像一个QThreadPool或只是一个QTimer如果你需要等待的东西.以下是关于Qt中替代方案的一些读法.
QConcurrent也更接近于c ++ 11 future,async例如,它还有可以运行的可选线程池.