线程和插槽QT

时间:2014-02-14 13:51:07

标签: qt

我写了这样的代码:

myworker.h

class myworker: public QObject
{    
Q_OBJECT

private:
    int var;
public:
    myworker();
    ~myworker();

signals:
    void finished();

public slots:
    void chgvar();
    void doWork();

};

myworker.cpp

void myworker::doWork()
{
    qDebug() <<"doWork  "<<"Thread ID:  "<< QThread::currentThreadId()<< endl;
    while(1){
        switch (var)
        {
        case 1:
           emit finished();
        };
    }
}

myworker::myworker()
{
    var=0;
}

myworker::~myworker()
{

}

void myworker::chgvar()
{
    var =1;
}

的main.cpp

int main(int argc, char *argv[]) 
{

    QApplication a(argc, argv);


    QPushButton *var= new QPushButton("chg var");
    QPushButton *dowork= new QPushButton("do work");
    QHBoxLayout *layout = new QHBoxLayout;

    QWidget *window     = new QWidget;
    layout->addWidget(var);
    layout->addWidget(dowork);

    window->setLayout(layout);

    QThread* thread = new QThread;
    myworker* work = new myworker();


    QObject::connect(thread, SIGNAL(started()), work , SLOT(dowork()));
    QObject::connect(var, SIGNAL(clicked()), work , SLOT(chgvar()));
    QObject::connect(work , SIGNAL(finished()), thread, SLOT(quit()));
    QObject::connect(work , SIGNAL(finished()), work , SLOT(deleteLater()));
    QObject::connect(work , SIGNAL(finished()), thread, SLOT(deleteLater()));*/

    work ->moveToThread(thread);
    thread->start();
    window->show()
    return a.exec();
}

当线程启动时,调用插槽dowork,直到变量var等于1.但是当单击改变了var值的按钮(var)时,不会执行插槽。有人能说出是否有错误吗?

感谢您的帮助

5 个答案:

答案 0 :(得分:2)

你把工人搬到了线上 - 好动 糟糕的举动是doWork()具有不定式循环。现在发生的事情是:

  1. 线程发出信号started()
  2. Qt检测到该worker被移动到其他线程,因此在您的线程的事件循环中排队执行doWork()个槽。
  3. 线程会执行您的广告位doWork(),并且由于您在doWork()中有不定式循环,因此会永久占用。
  4. 现在同样的sory与chgvar()位置相同。 Qt检测到目标对象在其他线程中,因此它将chgvar()
  5. 的执行排队
  6. 但是现在事件循环永远不会得到控制,所以永远不会调用chgvar()(它会在doWork()完成其工作之前一直存在)
  7. 所以你有某种死锁
  8. 热修复吗? 更改连接类型:

    QObject::connect(var, SIGNAL(clicked()), work , SLOT(chgvar()), Qt::DirectConnection);
    

    现在其他的多线程问题已经解决,所以你必须使用MUTEX来访问var,你应该将其标记为volatile,这样编译器就不会优化对它的访问并破坏代码。

答案 1 :(得分:1)

问题是你的循环永远不会让你的线程进入EventLoop,因此使用一个计时器:

myworker::myworker()
{
    var = 0;
    timer = new QTimer(this);
    timer->setIntervall(100);
    connect(timer,SIGNAL(timeout()),this,SLOT(doWork()));
    timer->start();
}

void myworker::doWork()
{
    qDebug() <<"doWork  "<<"Thread ID:  "<< QThread::currentThreadId()<< endl;
    if(var == 1)
       emit finished();
}

int main(int argc, char *argv[]) {

    QApplication a(argc, argv);


     QPushButton *var= new QPushButton("chg var");
     QPushButton *dowork= new QPushButton("do work");
     QHBoxLayout *layout = new QHBoxLayout;

     QWidget *window     = new QWidget;
     layout->addWidget(var);
     layout->addWidget(dowork);

     window->setLayout(layout);

     QThread* thread = new QThread;
     myworker* work = new myworker();

     QObject::connect(var, SIGNAL(clicked()), work , SLOT(chgvar()));
     QObject::connect(work , SIGNAL(finished()), thread, SLOT(quit()));
     QObject::connect(work , SIGNAL(finished()), work , SLOT(deleteLater()));
     QObject::connect(work , SIGNAL(finished()), thread, SLOT(deleteLater()));*/

     work->moveToThread(thread);
     thread->start();
     window->show()
     return a.exec();

}

答案 2 :(得分:0)

我认为你应该在实际完成循环时发出finished()信号,即当var的值等于1.我会按以下方式编写函数:

void myworker::doWork()
{
    qDebug() << "doWork  " << "Thread ID:  " << QThread::currentThreadId() << endl;
    while(!var){
        qDebug() << "Wait...";
    }
    emit finished();
}

答案 3 :(得分:0)

您的while(1)循环阻止了事件循环。事件永远不会被处理。这就是你永远不会调用你的插槽的原因。你应该考虑使用QTimer。请阅读this了解详情。

答案 4 :(得分:0)

您的代码中存在两个问题:

  1. 您的循环不是线程安全的。应使用原子操作设置和检查变量var。而且应该是不稳定的。
  2. (正如其他用户所说)直到你将线程工作流程发送到事件循环才会发出信号。