Qt4:while循环在单独的线程块UI中

时间:2013-03-05 08:13:32

标签: c++ multithreading qt4 qthread

所以我有一个简单的Qt4应用程序,它带有一个开始按钮,一个停止按钮和一个文本字段。按下“开始”按钮时,会生成一个新线程,该线程会不断递增计数器(在while循环中),并更新文本字段以通过信号/插槽反映这一点。按下“停止”按钮后,计数停止,直到再次按下“开始”按钮。

它有效......有点儿。它每秒只更新一次计数器;我希望它更快,比如每秒44100次。但是,取出sleep(1)调用会导致while循环被阻塞,没有识别出GUI事件,并且应用程序冻结。此外,停止按钮仅适用于第二次尝试?

当我继承QThread时,这曾经工作得非常好,但我被告知不要这样做,所以我尝试用子类化QObject然后将对象移动到QThread来制作解决方案......但它不是和以前一样工作。

以下是代码:

Worker.h

class Worker : public QObject
{
  Q_OBJECT

  public:
    Worker();

  public slots:
    void process();
    void stopRunning();

  signals:
    void signalValueUpdated(QString);

  private:
    bool running;
};

Worker.cpp

#include "Worker.h"

void Worker::process()
{
    qDebug("Worker thread id %d",(int)QThread::currentThreadId());

    static int value=0;
    running = 1;
    while(running == 1)
    {
        QString string = QString("value: %1").arg(value++);
        sleep(1); //I want to take this out or make it way shorter but I can't without it crashing.

        emit signalValueUpdated(string);

        QCoreApplication::processEvents();       
    }
}

void Worker::stopRunning()
{
    qDebug("stopRunning() invoked");
    running = 0;
}

MainWindow.h

class MainWindow : public QWidget
{
  Q_OBJECT

  public:
    MainWindow(QWidget *parent = 0);

  private:
    //Widgets
    QHBoxLayout * boxLayout;
    QPushButton * startButton;
    QPushButton * stopButton;
    QLineEdit * lineEdit;

    //Thread where the worker lives
    QThread * workerThread;
    //Worker object itself
    Worker * worker;
};

MainWindow.cpp

#include "MainWindow.h"

 MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
{
    boxLayout = new QHBoxLayout(this);
    startButton = new QPushButton("Start Counter", this);
    stopButton = new QPushButton("Stop Counter", this);
    lineEdit = new QLineEdit(this);

    boxLayout->addWidget(startButton);
    boxLayout->addWidget(stopButton); 
    boxLayout->addWidget(lineEdit);

    qDebug("Thread id %d",(int)QThread::currentThreadId());

    workerThread = new QThread;
    worker = new Worker();
    worker->moveToThread(workerThread);

    connect( startButton, SIGNAL(clicked()), workerThread, SLOT(start()), Qt::QueuedConnection ); //When the start button is clicked, start the worker thread
    connect( startButton, SIGNAL(clicked()), worker, SLOT(process()), Qt::QueuedConnection ); //When the start button is clicked, start the worker thread
    connect( workerThread, SIGNAL(started()), worker, SLOT(process()), Qt::QueuedConnection ); //When the worker thread starts, begin the Worker object's process function
    connect( stopButton, SIGNAL(clicked()), worker, SLOT(stopRunning()), Qt::QueuedConnection ); //When the stop button is clicked, invoke the Worker's stopRunning()
    connect( worker, SIGNAL(signalValueUpdated(const QString&)), lineEdit, SLOT(setText(const QString&)), Qt::QueuedConnection ); //When the Worker emits a signalValueChanged, update the lineEdit to reflect this

}

在Worker.cpp中没有sleep(1)和processEvents(),整个事情崩溃了,但是它们会慢下来,只是每秒更新一次而不是1000或更多。如何使while(running)循环不阻塞?

提前致谢!仍然试图围绕在Qt中进行多线程处理的最佳方式。

1 个答案:

答案 0 :(得分:2)

  1. 如果您不需要,请删除worker中的QCoreApplication::processEvents()(为什么需要它?GUI事件应该已经由主线程处理...)。这可能是您的问题的原因。

  2. 以正确的方式连接线程信号:

    connect(workerThread, SIGNAL(started()), worker, SLOT(process()));
    connect(startButton, SIGNAL(clicked()), thread, SLOT(start()));
    

    (删除startButton.clicked() - > worker.process()的连接 - 它没用,并且没有按照评论中的内容执行操作)

    为什么要删除它?

    因为将按钮直接连接到worker中的进程是不对的。您应该将按钮连接到Thread的开头,然后将Thread(已启动)连接到worker process()。避免直接连接应该避免您遇到的GUI冻结问题。

  3. 此外,您需要创建一个新线程并在每次单击按钮时“触发”它。您可以通过将按钮连接到窗口中的SLOT并从中创建线程(在MainWindow构造函数中创建它不起作用)来完成。


    取自(工作)计划,我有:

      // You need another slot in MainWindow, let it be "startProcessing()"
      // in MainWindow::MainWindow, connect the start button to startProcessing()
      connect(btnStart, signal(clicked(), this, SLOT(startProcessing())
    
    
      // inside the startProcessing slot
      void MainWindow::startProcessing() {
         ...
         Worker* worker = new Worker;
         QThread* thread = new QThread;
    
         // start the work
         worker->moveToThread(thread);
         connect(thread, SIGNAL(started()), worker, SLOT(process()));
    
         // Take care of cleaning up when finished too
         connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
         connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
         connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    
         thread->start(); 
      }
    

    您可能已经注意到,我也添加了代码来清理它(deleteLater())。

    停止按钮也会给你一些问题,但你现在应该知道如何继续。