一杯清酒邀明月
天下本无事,庸人扰之而烦耳。

  之前对线程理解得不深入,所以对Qt的线程机制没有搞清楚,今天写一篇文章总结一下,如有错误,欢迎指出。

       首先需要理解线程是什么,线程在代码中的表现其实就是一个函数,只不过这个函数和主线程的函数同时运行,写C语言的都知道,一般代码是从main()函数开始运行的,每个线程都有一个入口函数,main()函数可以看做是主线程的入口函数,从main函数开始执行,主线程就开始了,写过一点代码的都知道,程序是从main()函数开始一条一条地往下执行的,但是有的时候我们需要同时执行A,B两个函数。初学代码时,都是先调用A函数,再调用B函数,这时是A函数执行完毕后再执行B函数,没有达到我们想要同时执行的目的。这时如果把A函数放入另一个线程中执行,那么不需要等到A函数执行完毕,B函数就可以开始执行。C++11中已经有了多线程库,简单示例如下

1 std::thread t(A);
2 B();

       你可以随便写两个函数,函数名为A,B。函数内容可以写成输出10000次A(B函数可以输出10000次B,输出次数少了可能会观察不到),你可能会发现A和B会交替出现,这就是A和B在同时执行的证明。多线程在图形界面程序中几乎是必须的,图形界面程序的主线程一般是界面线程,用于响应用户的操作,后台线程用于执行计算,通信等操作,如果不使用多线程,图形界面会因为等待计算数据(当然我说的是大量数据,少量数据你可能会感受不到)而卡住不响应用户的操作。讲到这里你也许对线程有了一个基本的印象。

  Qt使用QThread类有两种方式,这个网上可以找到很多资料。

  第一种:继承QThread类,自己写一个类(假设为MyThread),重写QThread的run()函数,新线程就会运行run()里面的代码,但是要注意的是只有run()函数里面的代码在新线程里运行,所以你自己的MyThread类里面的槽函数虽然和主线程的信号绑定了,但是只要没有放在run()里面运行,还是运行在主线程中的。

  第二种:使用moveToThread(),我下面的示例代码就是使用的moveToThread()方法。QThrad中默认的run()函数启用了事件循环(exec()),所以你移动到线程中的那个对象的所有槽函数均在新线程中执行,不会阻塞主线程。看完示例就明白了。新建一个QApplication工程,把mainwindow.h改成下面的代码

 1 // mainwindow.h#ifndef MAINWINDOW_H
 2 #define MAINWINDOW_H
 3 #include <QApplication>
 4 #include <QObject>
 5 #include <QEvent>
 6 #include <thread>
 7 #include <iostream>
 8 #include <QThread>
 9 #include <QPushButton>
10 #include <QVBoxLayout>
11 #include <QMainWindow>
12 
13 // network thread
14 class NetworkThread:public QObject
15 {
16     Q_OBJECT
17 public:
18     NetworkThread()
19     {
20         // do some initial works;
21     }
22 
23 signals:
24     void datacoming(int a);
25 
26 private:
27     void memberFun();
28 
29 public slots:
30     void testSlot();
31     void sleepSlot();
32 };
33 // network thread class
34 
35 // GUI class,run in main thread
36 
37 class MyWidget:public QMainWindow
38 {
39     Q_OBJECT
40 
41 public:
42     QPushButton *firstButton,*secondButton,*thirdButton;
43 
44     QVBoxLayout *layout;
45     QWidget *p;
46 
47 public:
48     explicit MyWidget(QWidget *parent);
49     ~MyWidget();
50 signals:
51     void signalTestStart(int a=0);
52     void startNetworkSleep();
53 
54 public slots:
55     void secondButtonClicked();
56 };
57 
58 // GUI class
59 
60 // csApplication class
61 
62 class csApplication:public QApplication
63 {
64     Q_OBJECT
65 
66 public:
67     csApplication(int argc,char *argv[]);
68 
69     MyWidget *mywindow;
70     NetworkThread *netthd;
71     QThread *t;
72 
73     ~csApplication();
74 
75 
76 };
77 
78 // csApplication class
79 
80 
81 #endif // MAINWINDOW_H

把main.cpp改成下面的代码,并删去mainwindow.cpp

  1 // main.cpp
  2 
  3 #include "mainwindow.h"
  4 
  5 
  6 
  7 // network thread
  8 
  9 void NetworkThread::testSlot()
 10 {
 11     std::cout<<"\nin testSlot()\n thread id:"<<std::this_thread::get_id()<<std::endl;
 12     memberFun();
 13 }
 14 
 15 void NetworkThread::memberFun()
 16 {
 17     std::cout<<"\nin NetworkThread::memberFun()\nthread id:"<<std::this_thread::get_id()<<"\n"<<std::endl;
 18 }
 19 
 20 void NetworkThread::sleepSlot()
 21 {
 22     std::cout<<"in NetworkThread::sleepSlot()\n thread id:"<<std::this_thread::get_id()<<"\nthen sleep 5 seconds\n";
 23     QThread::sleep(5);
 24     std::cout<<"sleepSlot() weak up\n"<<std::endl;
 25 }
 26 
 27 // network thread class
 28 
 29 // GUI class,run in main thread
 30 
 31 MyWidget::MyWidget(QWidget *parent=0)
 32 {
 33     firstButton = new QPushButton(tr("first"));
 34     secondButton = new QPushButton(tr("second"));
 35     thirdButton = new QPushButton(tr("third"));
 36 
 37     layout = new QVBoxLayout;
 38     layout->addWidget(firstButton);
 39     layout->addWidget(secondButton);
 40     layout->addWidget(thirdButton);
 41 
 42     p=new QWidget;
 43 
 44     p->setLayout(layout);
 45 
 46     setCentralWidget(p);
 47 
 48 }
 49 MyWidget::~MyWidget()
 50 {
 51     delete firstButton;
 52     delete secondButton;
 53     delete thirdButton;
 54     delete p;
 55     delete layout;
 56 }
 57 
 58 void MyWidget::secondButtonClicked()
 59 {
 60     emit startNetworkSleep();
 61     std::cout<<"in MyWidget::secondButtonClicked()\n thread id: "<<std::this_thread::get_id()<<"\n"<<std::endl;
 62 }
 63 
 64 // GUI class
 65 
 66 // csApplication class
 67 
 68 csApplication::csApplication(int argc, char *argv[]):QApplication(argc,argv)
 69 {
 70 
 71     std::cout<<"\nin csApplication()\nthread id:"<<std::this_thread::get_id()<<"\n"<<std::endl;
 72     mywindow = new MyWidget();
 73     netthd = new NetworkThread();
 74     t = new QThread();
 75 
 76     connect(mywindow->firstButton,SIGNAL(clicked()),netthd,SLOT(testSlot()),Qt::QueuedConnection);
 77     connect(mywindow->secondButton,SIGNAL(clicked()),mywindow,SLOT(secondButtonClicked()));
 78     connect(mywindow,SIGNAL(startNetworkSleep()),netthd,SLOT(sleepSlot()),Qt::QueuedConnection);
 79 
 80     netthd->moveToThread(t);
 81     t->start();
 82     mywindow->show();
 83 
 84 }
 85 csApplication::~csApplication()
 86 {
 87     delete mywindow;
 88     delete netthd;
 89     delete t;
 90 }
 91 
 92 // csApplication class
 93 
 94 
 95 int main(int argc, char *argv[])
 96 {
 97     csApplication a(argc, argv);
 98 
 99     return a.exec();
100 }

点击运行就可以了。

posted on 2024-02-29 18:51  一杯清酒邀明月  阅读(52)  评论(0编辑  收藏  举报