Qt创建多线程的两种方式

一般简单的业务场景不需要创建子线程,但是当有复杂的业务逻辑时,主线程(UI线程)需要等待这个业务处理完毕,例如,在一个单线程中产生一千万一个随机数,这时再拖动鼠标点击窗口会发生卡顿,影响用户体验。需要注意的是,只有主线程才能操作UI窗口,当子线程需要向窗口某个控件传递数据时,只能将数据传递给主线程(信号和槽),再由主线程操作窗口。Qt中的创建子线程有两种方式。

方法一:

  1、创建一个线程子类,让其继承于QThread类

class MyThread:public Qthread
{
           ...
}

  2、在我们写的线程类中重写父类的run()方法

class MyThread:public Qthread
{
           ...
     void run() override;
         ...
}
 MyThread::void run() 
{
     //这是子线程的业务逻辑
}

  3、在UI线程中创建子线程对象,在某个契机启动子线程run方法。

...
MyThread *mythread = new MyThread;
...

connect(ui->pushbutton,&QPushButton::clicked,this,[=](){
     mythread->start();
});

一个demo,一个线程产生随机数,一个线程将这些随机排序。再由主线程将这两组数据显示在主窗口中控件中。

mythread.h

class GenRandom : public QThread
{
    Q_OBJECT
public:
    explicit  GenRandom(QObject *parent = nullptr);
    void run() override;
public slots:
    void getnum(int);   //槽函数接受主线程发送来num
signals:
    void sendvector(QVector<int>);  //将随机数发送给主线程
private:
    int m_num;  //由主线程告诉子线程产生多少个随机数
    QVector<int> m_v;

};

mythread.cpp

void GenRandom::getnum(int  n)
{
    m_num=n;
}
//重写,生成随机数
void GenRandom::run()
{
    qDebug()<<"线程号:"<<Generate::currentThreadId();
    for(int i=0;i<m_num;i++)
    {
        m_v.push_back(rand()%100);

    }
    emit sendvector(m_v);  //将数据发送给ui线程
}

ui线程:widget的构造函数

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    GenRandom *random = new GenRandom;
    //告诉子线程产生随机数的个数
    connect(this,&Widget::sendnum,gen,&GenRandom::getnum);
     //启动子线程
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        emit sendnum(1000);
        random->start();
    });
       //子线程将1000个数传递过来,主线程显示这1000个随机数
        connect(random,&GenRandom::sendvector,this,[=](QVector<int> list){
      
        for(int i=0;i<list.size();i++)
        {
            ui->listWidget_random->addItem(QString::number(list.at(i)));
        }
    });
}

排序线程写在mythread文件中。

.h

class Qsort:public QThread
{
    Q_OBJECT
public:
    explicit Qsort(QObject *parent=nullptr);
    void run() override;
protected:
    void quicksort(QVector<int> &m_v,int low,int high);
    int partiton(QVector<int> &m_v,int low,int high);
public slots:
    void getarray(QVector<int> list); //获取随机数
signals:
    void finishsort(QVector<int>);  //排序完成后发送给ui
private:
    QVector<int>  m_v;
};

.cpp

void Qsort::run()
{
    qDebug()<<"快速排序的线程:"<<Qsort::currentThreadId();
  
    quicksort(m_v,0,m_v.size()-1);

    emit  finishsort(m_v);
   
}

void Qsort::quicksort(QVector<int>& m_v, int low, int high)
{

    if(low<high)
    {
        int pos=partiton(m_v,low,high);
        quicksort(m_v,low,pos-1);
        quicksort(m_v,pos+1,high);
    }

}

int Qsort::partiton(QVector<int> &m_v, int low, int high)
{
    int pivot = m_v[low];
    while (low<high) {
        while(low<high&&m_v[high]>=pivot)
            --high;
        m_v[low]=m_v[high];
        while (low<high&&m_v[low]<=pivot)
            ++low;
        m_v[high]=m_v[low];
    }
    m_v[low]=pivot;
    return low;
}

void Qsort::getarray(QVector<int> list)
{
    m_v=list;
}

ui线程:widget的构造函数

//创建对象
  Qsort *q=new Qsort;
//接受随机线程发送来随机数据
 connect(random,&GenRandom::sendvector,q,&Qsort::getarray);
//开启线程
 connect(random,&GenRandom::sendvector,this,[=](QVector<int> list){
       q->start();

    });
//接受排序线程发送来的有序数据
 connect(q,&Qsort::finishsort,this,[=](QVector<int> list)
   {
        for(int i=0;i<list.size();i++)
        {
            ui->listWidget_qsort->addItem(QString::number(list.at(i)));
        }
    });

 方法二:

  1、创建一个新的类,这个类从QObject派生

class  newthread:public QObject
{
    ...  
}

  2、在newthread类中添加公共的自定义函数,用来处理子线程逻辑,这个自定义函数可以有参数

class  newthread:public QObject
{
    public:
       void   mythread1(。);  
}

  3、在UI线程创建QThread子线程对象

QThread *thread = new QThread;

  4、在UI线程创建任务类,不能指定父对象

newthread  *worker = new newthread;

  5、将worker移动到子线程对象中

worker->movetoThread(thread);

  6、启动子线程,但是此时任务类中自定义函数并没有工作,通过信号和槽的方式,启动工作函数。

以上面产生随机数中线程为例

//当收到主线程发送来的信号才真正开始   
connect(this,&MainWindow::starting,gen,&GenRandom::work_Gen);

connect(ui->pushButton,&QPushButton::clicked,[=](){
        emit starting(1000);
        thread1->start();
 });

 

上一篇:Qt-注意隐式共享机制


下一篇:Linux守护进程daemon