gpt4 book ai didi

c++ - 在另一个线程上向 QObject 发出信号的正确方法?

转载 作者:太空狗 更新时间:2023-10-29 20:52:37 24 4
gpt4 key购买 nike

假设我有一个位于另一个线程中的 slave 对象。我想告诉它在该线程上执行 A、B、C。我可以想到 3 种方法:

(1) 使用QTimer::singleShot

(2) 使用QMetaObject::invokeMethod

(3) 创建另一个master对象并将其信号连接到slave

示例如下:

class slave : public QObject
{
QThread thread_;

friend class master;
void do_A(params);
void do_B(params);
void do_C(params);

public:
slave() { thread_.start(); moveToThread(&thread_); }
~slave() { thread_.quit(); thread_.wait(); }

void que_A(params) { QTimer::singleShot(0, [&](){ do_A(params); }); } // (1)

void que_B(params) { QMetaObject::invokeMethod(this, "do_B", params); } // (2)
}

class master : public QObject // (3)
{
Q_OBJECT

public:
master(slave* s) { connect(this, &master::que_C, s, &slave::do_C); }

void do_C(params) { emit que_C(params); }

signals:
void que_C(params);
}

我的担忧是:

(1) 我在滥用 QTimer

(2) signals/slot 使用字符串,qt4 就是这样。 Qt5 使用 new syntax .

(3) 样板文件太多。

与其他方法相比,是否有任何方法被认为更正确?或者谁能​​想到更好的方法?

请说明为什么应该选择一种方法而不是其他方法的原因(不仅仅是意见)。

更新:

在我的实际应用程序中,我有另一个类——我们称它为 owner——它拥有多个 slaveowner 需要根据用户输入告诉不同的 slave 做不同的事情(A、B 或 C)。 slave 是有状态对象,所以我看不到使用并发函数的简单方法(例如,std::asyncQtConcurrency)。

最佳答案

好吧,我不会评论 (1) 和 (2),但我必须说 (3) 是通常使用的。但是,我理解您对过多样板文件的担忧。毕竟,创建一个单独的信号,比如 doActionA(),通过 QueuedConnection 将其连接到某个真实的 actionA() 并最终发出它。 ..太多的噪音和无用的 Action 。

事实上,它给您的唯一好处是松散耦合(您可以发送一个信号,而不知道是否存在与其连接的插槽)。但是,如果我创建一个名称为 doActionA() 的信号,我当然知道 actionA() 存在。那么问题开始出现了“为什么我必须写所有这些东西?”

同时,Qt 某种程度上提供了这个问题的解决方案,使您能够将自己的事件发布到任何事件循环(正如您所知,QThread 有一个)。因此,只需实现一次,您就不需要再编写大量的 connect emit 东西了。此外,我想我的效率更高,因为总而言之,通过 QueuedConnection 进行的每个插槽调用都只是在事件循环中发布一个事件。

此处InvokeAsync将成员函数执行的事件发布到QObject所在线程的事件循环中:

#include <QCoreApplication>
#include <QEvent>
#include <QThread>

#include <string>
#include <iostream>
#include <type_traits>
#include <functional>

template<typename T, typename R, typename ... Params, typename... Args>
void InvokeAsync(T* object, R (T::*function)(Params...), Args&&... args)
{
struct Event : public QEvent
{
std::function<R ()> function;
Event(T* object, R (T::*function)(Params...), Args&& ... args)
: QEvent{ QEvent::None },
function{ std::bind(function, object, std::forward<Args>(args)...) }
{
}
~Event() { function(); }
};

QCoreApplication::postEvent(object, new Event{ object, function, std::forward<Args>(args)... });
}

struct Worker : QObject
{
void print(const std::string& message, int milliseconds)
{
QThread::currentThread()->msleep(milliseconds);
std::cout << message
<< " from thread "
<< QThread::currentThreadId() << std::endl;
}
};

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

std::cout << "GUI thread " << QThread::currentThreadId() << std::endl;

QThread thread;
thread.start();

Worker worker;
worker.moveToThread(&thread);

InvokeAsync(&worker, &Worker::print, "Job 1", 800);
InvokeAsync(&worker, &Worker::print, "Job 2", 400);
InvokeAsync(&worker, &Worker::print, "Job 3", 200);

a.exec();

return 0;
}

输出:

GUI thread 00000000000019C8
Job 1 from thread 00000000000032B8
Job 2 from thread 00000000000032B8
Job 3 from thread 00000000000032B8

如您所见,所有作业都按照调用顺序在不同的线程中完成。 Qt 保证具有相同优先级的事件按发布的顺序进行处理。

也可以,如果 worker 位于 GUI 线程中。事件将仅在 GUI 事件循环中发布并在稍后处理(这就是为什么我称这些为 Async)。

如果您发现任何错误或有任何意见,请在评论中写下,我们会解决。

关于c++ - 在另一个线程上向 QObject 发出信号的正确方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45717265/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com