一、多线程中的信号与槽
1、QThread类拥有发射信号和定义槽函数的能力(因为QThread继承自QObject)
(1)、关键信号
A、void start():线程开始运行时发射该信号
B、void finished():线程完成运行时发射该信号
C、void terminated():线程被异常中发射该信号
#ifndef TESTTHREAD_H #define TESTTHREAD_H #include <QThread> class TestThread : public QThread { Q_OBJECT public: explicit TestThread(QObject *parent = 0); void run(); signals: void testsignal(); protected slots: void testslot(); }; #endif // TESTTHREAD_H
#include "TestThread.h" #include <QDebug> TestThread::TestThread(QObject *parent) : QThread(parent) { connect(this, SIGNAL(testsignal()), this, SLOT(testslot())); } void TestThread::testslot() { qDebug() << "void TestThread::testslot()"; } void TestThread::run() { qDebug() << "void TestThread::run() begin"; for(int i=0; i<10; i++) { qDebug() << "TestThread::run() i=" << i; sleep(1); } emit testsignal();//发射信号 qDebug() << "void TestThread::run() end"; }
#ifndef MYOBJECT_H #define MYOBJECT_H #include <QObject> class MyObject : public QObject { Q_OBJECT public: explicit MyObject(QObject *parent = 0); signals: protected slots: void startslot(); void finishedslot(); void terminatedslot(); }; #endif // MYOBJECT_H
#include "MyObject.h" #include <QDebug> MyObject::MyObject(QObject *parent) : QObject(parent) { } void MyObject::startslot() { qDebug() << "void MyObject::startslot()"; } void MyObject::finishedslot() { qDebug() << "void MyObject::finishedslot()"; } void MyObject::terminatedslot() { qDebug() << "void MyObject::terminatedslot()"; }
#include <QtCore/QCoreApplication> #include "TestThread.h" #include "MyObject.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); TestThread t; MyObject obj; QObject::connect(&t, SIGNAL(started()), &obj, SLOT(startslot())); QObject::connect(&t, SIGNAL(finished()), &obj, SLOT(finishedslot())); QObject::connect(&t, SIGNAL(terminated()), &obj, SLOT(terminatedslot())); t.start(); return a.exec(); }
2、概念小科普
(1)、进程中存在栈空间的概念(区别于栈数据结构)
(2)、栈空间专用于函数调用(保存函数参数、局部变量等)
(3)、线程拥有独立的栈空间(可调用其它函数)
3、小结论:只要函数中没有访问临界资源的代码,同一个函数可以被多个线程调用,且不会产生任何副作用(因为用的自己的栈空间)
4、实验前的准备
(1)、操作系统通过整型标识管理进程和线程
A、进程拥有全局唯一的ID值(PID)
B、线程拥有进程内唯一的ID值(TID)
(2)、QThread中关键的静态成员函数
A、QThread* currentThread()
B、Qt::HANDLE currentThreadId()
int main(int argc, char *argv[]) tid void TestThread::run() 0x56c TestThread::run() i= 0 void MyObject::startslot() 0x1018 //比TestThread::run() i= 0打印迟,说明线程是并行执行的 TestThread::run() i= 1 TestThread::run() i= 2 TestThread::run() i= 3 TestThread::run() i= 4 TestThread::run() i= 5 TestThread::run() i= 6 TestThread::run() i= 7 TestThread::run() i= 8 TestThread::run() i= 9 void TestThread::run() end void TestThread::testslot() 0x1018 void MyObject::finishedslot() 0x1018
在主线程、MyThread线程以及各个槽函数加上打印线程的ID号后,打印结果如上所示,发现各个槽函数都是在mian函数被调用(原因请听下回分解)
二、小结
(1)、QThread类用于发射信号和定义槽函数的能力
(2)、线程在进程内拥有一个唯一的ID值
(3)、线程拥有独立的栈空间用于函数调用
(4)、没有临界资源的函数可以无副作用被多个线程调用
(5)、槽函数的调用在某一线程中完成