【问题标题】:Qt: How do I catch signals from multple threads in a slot where all signals are queuedQt:如何在所有信号都排队的插槽中捕获来自多个线程的信号
【发布时间】:2013-12-09 18:39:43
【问题描述】:

我的情况是,我的应用程序中有未知数量的第 3 方线程调用回调。该回调在调用它的线程的上下文中发出一个信号。总是相同的信号,但 10 个不同的线程可以在任何给定时刻发出它。

我想在我拥有的单个 QThread 的上下文中将所有这些 singlas 排队并使用适当的插槽处理它们。

我该怎么做?以下代码不起作用。虽然我看到它从不同的线程发出信号,但我的“On...”从未被调用过。

QObject::connect(this,SIGNAL(ProcessQueuedOutEvent(int)),
        this,
        SLOT(OnProcessQueuedOutEvent(int)),
        Qt::QueuedConnection);

【问题讨论】:

  • 嗯 - 'OutEvent' 是否采用回调中返回的辅助指针/int,因此可用于传输上下文?
  • 哦,我肯定必须将缓冲区复制到我的插槽中。我假设一旦函数返回,我得到的任何指针结构都会被删除。
  • 你的类“this”是 QThread 对象吗,拥有 QThread 是什么意思?
  • 是的。它“是”一个 QThread。
  • 继承自QThread?!如果您没有重新实现 Qt 处理线程的方式,那么您做错了:blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong

标签: multithreading qt


【解决方案1】:

您的 QThread 是否运行事件循环?它必须这样做才能接收信号:

Queued Connection 当控制权返回到 接收者线程的事件循环。该插槽在 接收者的线程。

基本上排队连接的工作方式如下:

  1. 始发者发出信号。
  2. Qt 创建一个事件并将其发布到接收者事件队列中。
  3. 接收器通过其事件队列,获取事件并将信号分派到连接的插槽中。

因此,如果您不运行事件队列,则会发布信号,但您的线程将永远不会收到它们。

所以基本上你的线程应该在 run() 中进行一些初始化,然后调用 exec() 并将其传递给 Qt。

如果您的线程除了检查信号还需要运行一些周期性操作,您可以使用 QTimer::singleShot 计时器将信号发布到同一线程。

见http://qt-project.org/doc/qt-4.8/threads-qobject.html#signals-and-slots-across-threads

PS。如果您通过排队连接传递指针,则指针必须在处理信号之前有效,这可能是在您发布信号的函数存在之后。一个常见的错误是将带有字符串的信号作为参数发布,这些参数存储在本地 char[] 缓冲区中。在访问缓冲区的那一刻,原始函数已经完成,字符串已经消失了。这些错误取决于线程调度,因此难以调试。如果您通过队列连接传递指针,它们必须是堆分配的,并且被调用者必须负责释放它们。

【讨论】:

    【解决方案2】:

    如果我正确理解了您的问题,那么您有一个由许多线程执行的回调函数。这个回调函数应该发出一个信号,连接到另一个线程中的对象中的插槽。

    我建议使用模式 (moveToThread) 创建一个线程接收器对象。然后使用 postEvent 方法来实现私有方法。调用是线程安全的(参数被复制)。

    因此您的回调可以直接安全地调用:

    OnProcessQueuedOutEvent 
    

    将事件发布到 QThread 事件循环。

    接收器.h

    class Receiver : public QObject
    {
        Q_OBJECT
    public:
        explicit Receiver( QObject* parent = 0 );
        virtual ~Receiver();
    
    public slots:
        void OnProcessQueuedOutEvent( int val );
    
    private slots:
        void OnProcessQueuedOutEventImpl( int val );
    
    private:
        QThread m_thread;
    };
    

    接收器.cpp

    Receiver::Receiver( QObject* parent )
        : QObject(parent)
    {
        moveToThread(&m_thread);
        m_thread.start();
    }
    
    Receiver::~Receiver()
    {
        // Gracefull thread termination (queued in exec loop)
        if( m_thread.isRunning() ) {
            m_thread.quit();
            m_thread.wait();
        }
    }
    
    void OnProcessQueuedOutEvent( int val )
    {
        QMetaObject::invokeMethod(this, "OnProcessQueuedOutEventImpl", Q_ARG(int,val));
    }
    
    void OnProcessQueuedOutEventImpl( int val )
    {
        // do stuff here
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多