之前对线程理解得不深入,所以对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 }
点击运行就可以了。