QT多线程的使用

1、场景一
根据需求把excel表格中的内容提取到sqlite中 ,1000条到5000条还好, 数量超过5000的时候界面就会失去响应 转圈 以为程序挂掉了 等了一段时间之后又好了 。参考博客https://blog.csdn.net/yao5hed/article/details/81108507找出了答案 。

因为读取大文件要很长时间,事件循环一直等待函数返回,这样导致阻塞事件循环。结果,GUI线程所有的绘制和交互都被阻塞在事件队列中,无法执行重绘等事件,整个程序就失去响应了。
例子:
这是常用方法(数量集过大就会发生阻塞)

  QFile* file = new QFile("E:\qtgui.index");
    file->open(QIODevice::ReadOnly);
    QTextStream *stream = new QTextStream(file);
    while(!stream->atEnd())
    {
        QString line = stream->readLine();
        ui->textEdit->append(line);
    }

解决这种阻塞问题有两种方法
1、手动强制事件循环
在任务中不断调用QCoreApplication::processEvents()手动强制事件循环,它会在处理完队列中所有事件后返回。但是如果两次函数调用的间隔时间不够短,用户仍能明显感觉到程序卡顿。所以在while循环最后加一行QApplication::processEvents();即可。 但是经测试这种办法会超级慢,如果对时间没要求的话可以考虑这种办法,否则还是放到子线程去实现把。
2**、多线程处理**。
Qt提供了三种方式:QThread、QRunnable / QThreadPool、QtConcurrent。其中最常用的是 QThread。
对于本例,使用QThread又有三种方法:信号与槽实现线程间通信、元对象系统实现线程间通信、分离线程与任务。
前两种也是跨线程调用函数的方法。使用QThread信号与槽实现线程间通信这是线程间通信比较常用的方法。代码:`

class ReadThread : public QThread
{
    Q_OBJECT
public:
    ReadThread(QObject* obj);
signals:
    void toLine(QString line);
protected:
    void run() Q_DECL_OVERRIDE;
private:
    QFile* file;
    QObject* m_obj;
};


ReadThread::ReadThread(QObject* obj):
    m_obj(obj)
{
    file = new QFile("E:\qtgui.index");
}


void ReadThread::run()
{
    file->open(QIODevice::ReadOnly);
    QTextStream *stream = new QTextStream(file);
    while(1)
    {
        while(!stream->atEnd())
        {
            QString line = stream->readLine();
            emit toLine(line);
            QThread::msleep(15);
        }
    }
}

需要把读取任务放到run()里,构造函数要传入GUI类的指针
在GUI线程的信号与槽机制这样:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ReadThread* thread = new ReadThread(this);
    thread->start();
    connect(thread,SIGNAL(toLine(QString)),this,SLOT(appendText(QString)) );
    connect(thread,SIGNAL(finished()),this,SLOT(FinishThread()) );
}


void MainWindow::appendText(QString lineTemp)
{
    ui->textEdit->append(lineTemp);
}

使用了QThread的静态函数msleep,因为读取的文件太大,每读取一行就要更新GUI,太耗资源,会导致GUI忙不过来,读一行后稍微休息一下,否则也会阻塞GUI。

QThread的子类一般不定义槽函数,这是不安全的,可能造成主线程和子线程同时访问它,除非使用mutex保护。 但可以定义signal,而且可以在run函数中发射, 因为信号发射是线程安全的。

发布了29 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42542969/article/details/89308590
今日推荐