Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Qt4:独立线程块GUI中的while循环_C++_Multithreading_Qt4_Qthread - Fatal编程技术网

C++ Qt4:独立线程块GUI中的while循环

C++ Qt4:独立线程块GUI中的while循环,c++,multithreading,qt4,qthread,C++,Multithreading,Qt4,Qthread,因此,我有一个简单的Qt4应用程序,它有一个开始按钮、一个停止按钮和一个文本字段。当按下开始按钮时,会产生一个新线程,该线程会不断增加计数器(在while循环中),文本字段会更新,以通过信号/插槽反映这一点。按下停止按钮时,计数停止,直到再次按下开始按钮 它是有效的。。。某种程度上。它每秒只更新计数器一次;我希望它跑得更快,比如说每秒44100次。但是,执行sleep(1)调用会导致while循环阻塞,无法识别GUI事件,并且应用程序会冻结。此外,停止按钮仅在第二次尝试时有效 当我对QThrea

因此,我有一个简单的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;
};
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;
};
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;
}
#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

}
main window.h

class Worker : public QObject
{
  Q_OBJECT

  public:
    Worker();

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

  signals:
    void signalValueUpdated(QString);

  private:
    bool running;
};
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;
};
main window.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;
}
#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中实现多线程的最佳方法

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

  • 以正确的方式连接螺纹信号:

    connect(workerThread, SIGNAL(started()), worker, SLOT(process()));
    connect(startButton, SIGNAL(clicked()), thread, SLOT(start()));
    
    (删除
    startButton.clicked()
    ->
    worker.process()
    -它是无用的,不会执行注释中所写的操作)

    为什么要删除它? 因为将按钮直接连接到辅助进程中的进程是不正确的。您应该将按钮连接到线程的开头,然后将线程(已启动)连接到辅助进程
    process()
    。避免直接连接应该可以避免您面临的GUI冻结问题

  • 此外,您需要创建一个新线程,并在每次单击按钮时“激发”它。您可以将按钮连接到窗口中的
    插槽
    ,然后从中创建线程(在
    main窗口
    构造函数中创建线程将不起作用)


    摘自我的(工作)计划:

      // 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()


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

    您知道
    QRunnable
    ?它表示一个工作项,然后可以通过
    QThreadPool::globalInstance()->start(runnable)
    运行该工作项,而不必担心运行它的目标线程。只是一个替代方案的想法。启动单个
    QThread
    实例更低级,
    QThreadPool
    QtConcurrent
    更高级。另外,我想问一下,您为什么要使用
    Qt::QueuedConnection
    ?您对流程的要求太高了-在这样一个紧密的循环中更新GUI。它可能会崩溃,因为工作事件队列对于单个进程(例如2Gb)来说太大了—请观察进程的工作内存。尝试每秒更新GUI 44100次没有什么意义-没有人能读到它!我这样做了,现在一旦process()启动(while()循环运行),就不会接受任何GUI输入——单击Stop按钮什么也不做,调试消息“stopRunning()invoked”永远不会出现。将processEvents()放回解决了以下问题。。。再次编辑:删除一个连接,这样一旦按下开始键,然后按下停止键,再次按下开始键什么都不做……那么你做错了——你的代码正在GUI线程中运行@MartinJames是对的,如果用户输入不被接受,那么您正在主(GUI)线程中运行worker。从按钮到工作的连接应该是问题所在!这肯定可以解释,我该怎么解决这个问题呢?我认为通过调用worker->moveToThread(workerThread)可以避免,worker对象将被移动到一个单独的线程,其代码将在那里运行。编辑:另外,调试打印输出显示的线程id不同…@user2134278我认为问题出在连接中。。。我将编辑答案并从一些工作代码中提取一个片段。