QThread 通信线程安全

Posted

技术标签:

【中文标题】QThread 通信线程安全【英文标题】:QThread communicate threadsafe 【发布时间】:2016-06-01 20:49:49 【问题描述】:

我知道在主线程中不允许调用另一个线程的函数。是否允许从另一个线程调用信号而没有任何问题?假设这段代码在 MainWindow 中:

thread->moveTOThread(obj); 发出 obj->Signal();

谢谢


或者这是要走的路:

 Obj.h
signals:
    void testSignal(); 
public slots:
void Func();

    MainWindow.h
    void testSignal(); 

    MainWindow.cpp
    thread->moveTOThread(obj); 
    connect(this,SIGNAL(testSignal()),obj,SIGNAL(testSignal()));
    emit testSignal(); 

    Obj.cpp
    connect(this,SIGNA(testSignal()),this,SLOT(Func()));

【问题讨论】:

【参考方案1】:

是的! 只要您使用信号的默认自动连接,就可以从任何线程调用信号。这样的槽/函子将在其上下文对象的线程中执行。例如,即使这些库不使用 Qt,您也可以从第三方库的回调中发出信号。

警告:任何显式直接连接的槽/函子都将在调用信号的线程中执行。

【讨论】:

你知道从另一个线程调用函数的方法是什么吗?为什么不直接从 main-gui-thread 中的另一个线程对象调用该函数?如果我只从那里调用其他线程的函数,我认为没有问题? @Bob 如果您调用的函数不是线程安全的,那么您将面临未定义的行为。您可能“看到”没有问题,但您可能正在默默地格式化您的硬盘。 我没有得到答案。我可以在程序不崩溃的情况下调用另一个线程的函数吗?为什么我应该使用 Signal 和 Slots 的额外代码。 @Bob 如果信号和插槽对您来说工作量太大,您也可以使用QMetaObject::invokeMethod。如果你直接调用一个函数,它将在你调用它的线程中运行。除非您调用的函数是线程安全的,否则您将面临获得race condition 的风险。【参考方案2】:

connect 采用第五个参数,即连接类型。 默认值AutoConnection 将使用线程安全的QueuedConnection 连接类型,假设在进行连接调用时对象位于不同的线程中。如果在建立连接时它们在同一个线程中,它将使用非线程安全的DirectConnection 类型的连接。

当控制返回到事件循环时,通过将槽调用作为事件在目标线程中调用它来排队来实现线程安全。

【讨论】:

当您使用Qt::AutoConnection 时,会在发出信号时进行检查,而不是在建立连接时进行检查。【参考方案3】:

我不能 100% 确定如果你这样做会发生什么。但是,您仍在跨越/打破线程边界 - 并且信号可能会从您调用的线程发出。

我相信更好的方法是将“调用”对象中的信号连接到“目标”对象中的信号。但即使这样也有点糟糕,因为信号会立即发出(也许这是你的意图),这类似于直接连接信号 - 在我看来,跨线程非常糟糕,除非你有很好的理由(我想不出)。

但是为什么不将信号连接到对象中的插槽,然后发出信号。这样可以保持线程边界?

您似乎正试图强制另一个线程中的信号立即运行...您的用例是什么?

【讨论】:

我只是想以某种方式调用 obj 的函数。由于 obj->Func();不是线程安全的我正在寻找一种线程安全的方式。我认为可能会从 obj 发出信号并将 obj 构造函数中的信号连接到 Slot Func()。我怎样才能调用 Func() 线程安全???? @Bob 假设Class B 是另一个线程中的对象,只需将来自Class A 的信号连接到Class B 中的插槽即可。您不必将来自Class B 的信号连接到Class B 中的插槽,然后调用此信号。 @Bob 好吧...如果您愿意,您可以直接调用该函数,没有人可以阻止您。但它打破了线程边界,这样做是不安全的。为了安全地调用你的对象函数,机制是发送一个信号......它就像两行代码一样!一根线连接,一根线发出信号(哦,是的,你需要声明信号)......就是这样!然后所有这些大惊小怪都消失了。或者,如果这是某种“帮助”函数,您不需要实例化对象,则可以将其设为静态函数……您的用例是什么?或者你的功能是做什么的?

以上是关于QThread 通信线程安全的主要内容,如果未能解决你的问题,请参考以下文章

线程安全的事件传递

QWidget中结束QThread线程

QThread::quit() 是立即结束线程还是等到返回事件循环?

QThread 线程间通信:连接到 &QThread::quit 与连接到 lambda [&thread] thread->quit(); 的奇怪行为

除了主 ui 线程之外,使用 QThread 设置图形时遇到问题

Java多线程 —— 线程安全线程同步线程间通信(含面试题集)