这种线程间通信方法安全吗?

Is this method of inter-thread-communication safe?

本文关键字:安全 方法 通信 线程      更新时间:2023-10-16

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

每个线程都连接到一个gui,消息在不同的线程之间发送。每个线程基本上都要处理它自己的列表。例如:

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

Obj 2:数据的生产者。它将数据推入它的列表。它有可用的插槽供其他"ping"它的数据,这将反过来从它的列表中发出一个信号弹出数据。没有其他对象可以直接访问此列表。

Obj 3:为Obj 1生成数据,并从Obj 2消费数据。它有自己的内部数据结构来跟踪发送到obj 1和来自obj 2的数据。在做了一些分析之后,最后将两个数据集推到某个QwtPlots

Obj的1和2是实时关键的,并使用QueryPerformanceCounter风格的"计时",这将在它们运行时基本上占用一个CPU。它们每个循环运行QCoreApplication::processEvents()来处理传入的事件。

这是处理跨线程数据共享的好方法吗?如果不是,漏洞在哪里,你会如何纠正它们?我知道这将创建大量的数据"副本",但是内存膨胀在这一点上不是一个问题。

提前感谢:)

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

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

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

Obj 2:数据的生产者。它将数据推入它的列表。它有可用的插槽供其他"ping"它的数据,这将反过来从它的列表中发出一个信号弹出数据。没有其他对象可以直接访问此列表。

你没有提到"ping"是如何实现的,或者哪些线程调用这些插槽。如果其他线程直接调用它们,并且ping涉及访问内部std::列表,那么您就有麻烦了。如果这些插槽只能通过排队或自动连接调用(例如,对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
}