【问题标题】:Is this method of inter-thread-communication safe?这种线程间通信的方法安全吗?
【发布时间】:2011-09-28 17:20:39
【问题描述】:

我有 3 个对象(继承自 QObject),每个对象都包含一个单独的 std::list。每个对象都在主 gui 线程(没有父线程)中创建,然后被推送到它自己的线程(使用 Qt 的QObject::moveToThread())。

每个线程都连接到一个 gui,并在不同线程之间发送带有数据的消息。每个线程本质上都是处理它自己的列表。例如:

Obj 1:数据消费者。它从列表的前面弹出(如果存在数据)以供使用。它还有一个可用的 SLOT,以便其他线程可以将数据推送到它。没有其他对象可以直接访问这个列表,只有原始的 QObject 类。

Obj 2:数据的生产者。它将数据推送到其列表中。它有 SLOTS 可供其他人“ping”它以获取数据,这些数据又会从其列表中发出 SIGNAL 弹出数据。没有其他对象可以直接访问此列表。

Obj 3:为 obj 1 生成数据并使用来自 obj 2 的数据。它有自己的内部数据结构,用于跟踪发送给 obj 1 的数据和来自 obj 2 的数据。它最终会推送这两个数据集一些QwtPlots 在做了一些分析之后。

Obj 的 1 和 2 是实时关键的,并且使用 QueryPerformanceCounter 样式的“计时”,这实际上会在它们运行时消耗 CPU。他们在每个循环中运行QCoreApplication::processEvents() 来处理发生的事件。

这是处理跨线程数据共享的好方法吗?如果不是,漏洞在哪里,你将如何纠正它们?我知道这会产生大量数据“副本”飞来飞去,但此时内存膨胀不是问题。

提前致谢:)

【问题讨论】:

    标签: c++ multithreading qt signals-slots qwt


    【解决方案1】:

    如果没有所有实现细节,很难准确地说它是否是线程安全的,因为使用线程时可能会出错。

    Obj 1:数据消费者。它从列表的前面弹出(如果存在数据)以供使用。它还有一个可用的 SLOT,以便其他线程可以将数据推送到它。没有其他对象可以直接访问这个列表,只有原始的 QObject 类。

    如果此插槽使用排队或自动连接类型连接到其他线程(例如 Obj 3)中的信号,则 Obj 1 可能是安全的。如果插槽是直接从其他线程调用的,那么它显然不是线程安全的,除非您显式同步所有内容。

    Obj 2:数据的生产者。它将数据推送到其列表中。它有 SLOTS 可供其他人“ping”它以获取数据,这些数据反过来会从其列表中发出 SIGNAL 弹出数据。没有其他对象可以直接访问此列表。

    您没有提到“ping”是如何实现的,也没有提到哪些线程调用了这些插槽。如果其他线程直接调用它们并且如果 ping 涉及访问内部 std::list,那么你就有麻烦了。如果这些插槽仅通过排队或自动连接调用(例如,对 Obj 3 中的某些信号),那很好。如果这些插槽是线程安全的(例如,它们只将“ping”消息放入某种内部同步消息队列中),那么也可以。不过,后一种方式看起来像是对排队连接机制的自定义重新实现。

    总的来说,这整件事对我来说太危险了,因为插槽可能会被错误地从任何地方调用。我会尝试通过在那里进行一些安全检查来避免这种事情,如下所示:

    void Obj2::ping() {
        if (QThread::currentThread() != this->thread()) {
            // not sure how efficient it is
            QMetaObject::invoke(this, "ping", Qt::QueuedConnection);
            return;
        }
        // thread unsafe code goes here
    }
    

    【讨论】:

    • Obj1 和 Obj2 从来没有任何直接调用的方法来处理它的内部数据。所有内部数据调用都是通过排队连接完成的(实际上是自动连接,但因为它们是不同的线程,排队连接)。 Obj 2 以下列方式被“ping”,Obj3 向 obj2 插槽发出信号。 obj2 采用当前列表结构并向 obj3 中的插槽发出信号。 Obj3 对该数据进行一些分析,然后向主 gu​​i 线程上的 qwtplot 实现的插槽发出信号以绘制数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多