2

我目前正在尝试了解 Qt 中的信号和插槽如何与线程一起工作。

我尝试使用以下代码运行一个小测试:

class Worker : public QObject{
    Q_OBJECT
public:
    Worker(int _value){value = _value;}
    ~Worker(){};
    int value;

public slots:
    void changeValue(int newValue){value = newValue;}
    void doWork(){
        while(1){
            _sleep(500);
            std::cout << "Value is " << value << std::endl;
            if(value == 0)break;
        }
        emit finished();
    }

signals:
    void finished();
};

class Manager : public QObject{
    Q_OBJECT
public:
    Manager(){}
    ~Manager(){};
signals:
    void modifiedValue(int value);
public:
    void changeTheValue(int value){emit modifiedValue(value);}
};

基本上,workervalue每隔一段时间就会显示它的成员,并且有一个带有修改值的函数的槽。

管理器的唯一目的是在被调用时发出具有新值的信号,该信号changeTheValue映射到 Worker 中修改value成员的插槽。

然后我让我的Worker班级通过以下方式在一个线程中工作:

QThread myThread;
Worker myWorker(10);
Manager manager;

myWorker.moveToThread(&myThread);
QObject::connect(&myThread, SIGNAL(started()), &myWorker,SLOT(doWork()));
QObject::connect(&myWorker, SIGNAL(finished()), &myThread, SLOT(quit()));
QObject::connect(&myWorker, SIGNAL(finished()), &myWorker, SLOT(deleteLater()));
QObject::connect(&myThread, SIGNAL(finished()), &myThread, SLOT(deleteLater()));
QObject::connect(&manager, SIGNAL(modifiedValue(int)), 
                 &myWorker, SLOT(changeValue(int)));
myThread.start();

for(int i = 1; i < 10 ; i++){
    _sleep(1000);
    manager.changeTheValue(i);
}
manager.changeTheValue(0);

但什么也没有发生。该值似乎没有改变:输出显示十几行带有Value is 10.

我不明白的是,为什么信号/槽映射Manager::modifiedValueWorker::changeValue似乎不起作用?仅仅是因为线程当前正在运行doWork()' 循环吗?那么对插槽的调用在哪里结束(排队,丢弃,其他)?

我找不到更多关于信号/插槽机制如何与线程一起工作的更多信息(我只找到了这个线程,它解释了对插槽的调用最终在哪个线程的调用堆栈中结束,但答案中提供的链接似乎已经过时并且导致 Qt 5 主页)。

总结一下问题:

  • 为什么对修改值的插槽的调用什么都不做?
  • 是否有可能使这项工作(在必要时添加线程安全)以及如何?
4

1 回答 1

3

信号和槽如何与线程一起工作有多种模式(您绝对必须使用QThreads 才能使这些工作!)。这些记录在手册中:http: //qt-project.org/doc/qt-4.8/threads-qobject.html#signals-and-slots-across-threads

您的代码中的错误是永远不会调用 Qt 事件循环(因为doWork永远不会返回)。对于重复呼叫,您应该在该线程中使用计时器。或者(不是推荐的解决方案)您可以processEvents在无限循环中调用。

于 2013-05-27T14:27:06.150 回答