关于Qt的槽函数和多次调用的问题

4

我正在学习Qt,有一个非常基础的问题。

如果在一个槽函数中存在(函数作用域)变量,并且该槽函数被多次调用,在上一次调用返回之前每次调用都会覆盖变量吗?也就是说,如果在上一次运行返回之前调用槽函数,那么这不会导致错误吗?

谢谢。

3个回答

3

如果这些调用是从不同的线程发起的并且您正在使用直接连接,则是可以的。

如果您使用了排队连接,那么槽函数调用将在事件循环上依次执行,该事件循环在您的接收对象所属的线程上运行。(感谢Idan K评论的编辑)。

请查看Signal and slots的排队连接或QMutexLocker来解决您的问题。


1
我相信排队连接会在QObject所附加的事件循环上运行。例如,如果您在QThread::run()内创建一个QObject,则其槽将在QThread的上下文中处理。 - Idan K
我不同意,但可能没有足够的信息来确定。如果它是一个函数作用域变量,在不同线程同时运行时就不应该被覆盖。在这种情况下,它应该能正常工作。然而,如果它是函数作用域的引用或指针变量,则源数据可能已经改变,这可能会引起问题。 - Caleb Huitt - cjhuitt

1
如果你真正使用函数作用域变量,那么它就无关紧要。例如:
class WheelSpinner : public QThread
{
Q_OBJECT;
public:
    WheelSpinner( QObject* receiver, const char* slot )
    {
        connect( this, SIGNAL( valueChanged( int ) ), receiver, slot,
                 Qt::DirectConnect );
    }

    void run()
    {
        for ( int i = 0; i < 100000; ++i )
        {
            emit ( valueChanged( i ) );
        }
    }

public signals:
    void valueChanged( int value );
};

class ProgressTracker : public QObject
{
Q_OBJECT;
public:
    ProgressTracker() { }

public slots:
    void updateProgress( int value )
    {
        // While in this function, "value" will always be the proper 
        // value corresponding to the signal that was emitted.
        if ( value == 100000 )
        {
            // This will cause us to quit when the *first thread* that 
            // emits valueChanged with the value of 100000 gets to this point.
            // Of course, other threads may get to this point also before the 
            // program manages to quit.
            QApplication::quit();
        }
    }
};

int main( int argc, char **argv )
{
    QApplication app( argc, argv );
    ProgressTracker tracker;
    WheelSpinner spinner1( &tracker, SLOT( updateProgress( int  ) ) );
    WheelSpinner spinner2( &tracker, SLOT( updateProgress( int  ) ) );
    WheelSpinner spinner3( &tracker, SLOT( updateProgress( int  ) ) );

    spinner1.run();
    spinner2.run();
    spinner3.run();

    return ( app.exec() );
}

所以在这种情况下,你是说如果同一个WheelSpinner对象(比如spinner2)对i调用updateProgress,并且第i-1次调用还没有完成,它仍然会正常运行? - Anand
1
@trex279:首先,使用直接连接,如果spinner2为i调用updateProgress,则它将等待updateProgress函数完成后才会继续执行。该部分是顺序的。但是,如果spinner1在spinner2仍在运行i的相同函数时运行i + 1,则两者都将正确执行。 - Caleb Huitt - cjhuitt

1

2
一个重要的注意点是QObject::sender()不是可重入的。 - Macke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接