网站开发项目的里程碑,在线设计平台用户规模,页面设计属于作品登记的哪个类别,网店怎么开大概需要多少钱信号和槽是Qt的核心机制之一#xff0c;通过该机制大大简化了开发者的开发难度。信号和槽属于观察者模式#xff08;本质上是回调函数的应用#xff09;。是函数就需要考虑其是在那个线程中执行#xff0c;本文讨论的就是槽函数在那个线程中执行的问题。
目录
1. connect… 信号和槽是Qt的核心机制之一通过该机制大大简化了开发者的开发难度。信号和槽属于观察者模式本质上是回调函数的应用。是函数就需要考虑其是在那个线程中执行本文讨论的就是槽函数在那个线程中执行的问题。
目录
1. connect函数的第五个参数说明
2. 发送者和接收者在同一个线程创建
2.1 槽函数在发送者所在线程执行
2.3 槽函数不在发送者所在线程执行
3. 发送者和接收者在不同线程创建
3.1 槽函数在接收者所在线程执行
3.2 槽函数在发送者所在线程执行
4.发送者所在线程和发送信号线程的区别 1. connect函数的第五个参数说明 connect函数用来连接信号和槽类似于提前注册。其第五个参数默认是Qt::AutoConnection所以开发者很多时候可以忽略此参数。但是在牵扯到复杂业务开发尤其是多线程并发开发时往往需要关注第五个参数第五个参数取值和含义如下
Qt::AutoConnection 自动连接发送者和接受者在同一个线程时等同于Qt::DirectConnection不同线程等同于Qt::QueuedConnection
Qt::DirectConnection 直接同步连接槽函数在接受者所依附线程执行。
Qt::QueuedConnection 队列异步连接槽函数在发送信号的线程执行。异步连接的时候信号是由接收者所在的线程的事件处理机制来处理的如果接收者所在的线程没有事件处理的话这个信号就不会被处理
Qt::BlockingQueuedConnection 阻塞连接发送者和接收者在同一线程时会死锁
Qt::UniqueConnection 唯一连接防止信号和槽重复连接
Qt::SingleShotConnection 单次连接信号和槽函数只连接一次槽函数执行后连接会自动断开
2. 发送者和接收者在同一个线程创建
2.1 槽函数在发送者所在线程执行
发送者
sender.h
#ifndef SENDER_H
#define SENDER_H#include QObject
#include QStringclass Sender :public QObject {Q_OBJECTpublic:Sender(QObject* parent 0);public slots :void emitsig(const QString str, const int ci);signals:void sig(const QString str, const int ci);
};#endif // SENDER_Hsender.cpp
#include sender.h
#include QDebug
#include QThread
#include iostream
#include thread
#include QObjectSender::Sender(QObject* parent) : QObject(parent) {}void Sender::emitsig(const QString str, const int ci)
{qDebug() sender signal thread id is: QThread::currentThreadId() str ci;emit sig(str, ci);
}接收者
recver.h
#ifndef RECVER_H
#define RECVER_H#include QObject
#include QDebug
#include QThread
#include iostream
#include thread
#include QObjectclass Recver : public QObject
{Q_OBJECT
public:explicit Recver(QObject *parent nullptr);public slots :void slot(const QString str, const int ci);
};#endif // RECVER_Hrecver.cpp
#include recver.h
#include QDebug
#include QThread
#include iostream
#include thread
#include QObjectRecver::Recver(QObject *parent): QObject{parent}
{}void Recver::slot(const QString str, const int ci) {qDebug() recver slot thread id is: QThread::currentThreadId() str ci;
}main函数
main.cpp
#include QCoreApplication
#include QDebug
#include QThread
#include iostream
#include thread
#include QObject#include sender.h
#include recver.h
#include mythread.h/*
// QObject::connect函数的第五个参数Qt::AutoConnection自动连接发送者和接受者在同一个线程时等同于Qt::DirectConnection不同线程等同于Qt::QueuedConnectionQt::DirectConnection直接调用连接槽函数在接受者所依附线程执行。Qt::QueuedConnection异步调用连接槽函数在发送信号的线程执行。异步连接的时候信号是由接收者所在的线程的事件处理机制来处理的如果接收者所在的线程没有事件处理的话这个信号就不会被处理Qt::BlockingQueuedConnection阻塞连接调用发送者和接收者在同一线程时会死锁Qt::UniqueConnection防止信号和槽重复连接Qt::SingleShotConnection信号和槽函数仅只需单次连接槽函数执行后连接会自动断开
*//*
// Qt4和Qt5都适用的连接方式注意此方式是在Q5上可能会导致槽函数不被调用此时可尝试使用Qt5新的连接方式
QObject::connect(sender, SIGNAL(sig()), recver, SLOT(slot()), Qt::DirectConnection);
QObject::connect(sender, SIGNAL(sig()), recver, SLOT(slot()), Qt::QueuedConnection);
//QObject::connect(sender, SIGNAL(sig()), recver, SLOT(slot()), Qt::BlockingQueuedConnection);
QObject::connect(sender, SIGNAL(sig()), recver, SLOT(slot()), Qt::UniqueConnection);
QObject::connect(sender, SIGNAL(sig()), recver, SLOT(slot()), Qt::SingleShotConnection);
*//*
// Qt5最新的连接方式
QObject::connect(sender, Sender::sig, recver, Recver::slot, Qt::DirectConnection);
QObject::connect(sender, Sender::sig, recver, Recver::slot, Qt::QueuedConnection);
// 发送者和接收者在同一个线程将会死锁
//QObject::connect(sender, Sender::sig, recver, Recver::slot, Qt::BlockingQueuedConnection);
//QObject::connect(sender, Sender::sig, recver, Recver::slot, Qt::UniqueConnection);
QObject::connect(sender, Sender::sig, recver, Recver::slot, Qt::SingleShotConnection);
*/// 主线程获取
/*
QCoreApplication::instance()-thread();
*//*
// 关于Qt线程的使用说明
在Qt4.3(包括)之前run 是虚函数必须子类化QThread来实现run函数。
而从Qt4.4开始qthreads-no-longer-abstractrun 默认调用 QThread::exec() 。这样一来不需要子类化 QThread 了只需要子类化一个 QObject就够了
QThread中run对于线程的作用相当于main函数对于应用程序。它是线程的入口run的开始和结束意味着线程的开始和结束。
QThread所依附的线程就是创建线程的线程。
QThread管理的线程就是run中创建的线程。
*/// 连接多次发送信号槽函数也会多次触发
void test1() {Sender sender;Recver recver;QObject::connect(sender, Sender::sig, recver, Recver::slot);QObject::connect(sender, Sender::sig, recver, Recver::slot);qDebug() call first;sender.emitsig(fist, 110);qDebug() call second;sender.emitsig(second, 220);qDebug() call third;sender.emitsig(third, 330);
}// 接受对象虽然是线程对象但是槽函数却在发送对象所在线程对象执行因为接收者依附于发送对象所在线程
/*
QThread中slot和run函数共同操作的对象都会用QMutex锁住是因为slot和run处于不同线程需要线程间的同步。
*/
void test2() {Sender sender;Mythread mythread;// Mythread构造函数中去掉moveToThread(this);,槽函数将在主线程执行加上moveToThread(this)槽函数将在子线程执行// 加上moveToThread(this)后连接方式修改为Qt::DirectConnection槽函数在主线程中执行QObject::connect(sender, SIGNAL(sig(const QString, const int)), mythread, SLOT(slot_main(const QString, const int)));mythread.start();sender.emitsig(mythread, 440);
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);qDebug() main thead id is : QThread::currentThreadId();//std::cout std::this_thread::get_id() std::endl;Sender sender;Recver recver;QObject::connect(sender, Sender::sig, recver, Recver::slot);sender.emitsig(fist, 110);return a.exec();
}运行效果 可以看到槽函数在信号发送者所在线程主线程中执行。
2.3 槽函数不在发送者所在线程执行
main.cpp
#include QCoreApplication
#include QDebug
#include QThread
#include iostream
#include thread
#include QObject#include sender.h
#include recver.hint main(int argc, char *argv[])
{QCoreApplication a(argc, argv);qDebug() main thead id is : QThread::currentThreadId();//std::cout std::this_thread::get_id() std::endl;Sender sender;Recver recver;QObject::connect(sender, Sender::sig, recver, Recver::slot);QThread thread;recver.moveToThread(thread);thread.start();sender.emitsig(fist, 110);return a.exec();
}运行效果 代码中创建一个子线程对象并将接收者移动到子线程槽函数在子线程中执行。
3. 发送者和接收者在不同线程创建
3.1 槽函数在接收者所在线程执行
mythread.h
#ifndef MYTHRED_H
#define MYTHRED_H#include QThread class Mythread : public QThread
{
Q_OBJECTpublic:Mythread(QObject* parent 0);public slots:void slot_main(const QString str, const int ci);protected:void run();
};#endif // MYTHRED_Hmythread.cpp
#include mythread.h
#include QDebug
#include sender.hMythread::Mythread(QObject* parent) : QThread(parent)
{//moveToThread(this);
}void Mythread::slot_main(const QString str, const int ci) {qDebug() mythread slot_main: currentThreadId() str ci;
}void Mythread::run() {qDebug() mythread thread: currentThreadId();Sender sender;connect(sender, SIGNAL(sig(const QString, const int)), this, SLOT(slot_main(const QString, const int)));sender.emitsig(thread, 220);exec();
}main.cpp
#include QCoreApplication
#include QDebug
#include QThread
#include iostream
#include thread
#include QObject#include sender.h
#include recver.h
#include mythread.hint main(int argc, char *argv[])
{QCoreApplication a(argc, argv);qDebug() main thead id is : QThread::currentThreadId();//std::cout std::this_thread::get_id() std::endl;Mythread mythread;mythread.start();return a.exec();
}运行效果如下 如上显示在子线程发送信号槽函数却在主线程中执行因为接收者mythread是在主线程中创建。
3.2 槽函数在发送者所在线程执行
mythread.cpp
#include mythread.h
#include QDebug
#include sender.hMythread::Mythread(QObject* parent) : QThread(parent)
{moveToThread(this);
}void Mythread::slot_main(const QString str, const int ci) {qDebug() mythread slot_main: currentThreadId() str ci;
}void Mythread::run() {qDebug() mythread thread: currentThreadId();Sender sender;connect(sender, SIGNAL(sig(const QString, const int)), this, SLOT(slot_main(const QString, const int)));sender.emitsig(thread, 220);exec();
}main.cpp
#include QCoreApplication
#include QDebug
#include QThread
#include iostream
#include thread
#include QObject#include sender.h
#include recver.h
#include mythread.hint main(int argc, char *argv[])
{QCoreApplication a(argc, argv);qDebug() main thead id is : QThread::currentThreadId();//std::cout std::this_thread::get_id() std::endl;Mythread mythread;mythread.start();return a.exec();
}运行效果 将信号接收者构造函数//moveToThread(this);的注释放开槽函数在子线程中执行。尽管接收者在主线程中被创建。
如果构造函数注释moveToThread(this);connect第五个参数修改为Qt::DirectConnection槽函数也可以在子线程中执行如下
connect(sender, SIGNAL(sig(const QString, const int)), this, SLOT(slot_main(const QString, const int)), Qt::DirectConnection);
mythread.cpp
#include mythread.h
#include QDebug
#include sender.hMythread::Mythread(QObject* parent) : QThread(parent)
{//moveToThread(this);
}void Mythread::slot_main(const QString str, const int ci) {qDebug() mythread slot_main: currentThreadId() str ci;
}void Mythread::run() {qDebug() mythread thread: currentThreadId();Sender sender;connect(sender, SIGNAL(sig(const QString, const int)), this, SLOT(slot_main(const QString, const int)), Qt::DirectConnection);sender.emitsig(thread, 220);exec();
}信号发送者在子线程槽函数也在子线程中执行。
4.发送者所在线程和发送信号线程的区别 有很多人分不清发送者所在线程和发送信号的线程在此做一下区分说明。发送者所在线程指的是构造发送者对象所在的线程发送信号线程指的是发送信号所在的线程即调用emit所在的线程有些时候这两个线程并不是一个线程。前面说的槽函数在发送者所在线程执行指的是在发送者所在线程而不是发送信号的线程。如下代码
mythread.h
#ifndef MYTHRED_H
#define MYTHRED_H#include QThread
#include sender.hclass Mythread : public QThread
{
Q_OBJECTpublic:Mythread(QObject* parent 0);Mythread(Sender* sender);public slots:void slot_main(const QString str, const int ci);protected:void run();private:Sender* m_sender;
};#endif // MYTHRED_Hmythread.cpp
#include mythread.h
#include QDebugMythread::Mythread(QObject* parent) : QThread(parent)
{//moveToThread(this);m_sender nullptr;
}Mythread::Mythread(Sender* sender) {//moveToThread(this);m_sender sender;
}void Mythread::slot_main(const QString str, const int ci) {qDebug() mythread slot_main: currentThreadId() str ci;
}void Mythread::run() {qDebug() mythread thread: currentThreadId();if (m_sender) {connect(m_sender, SIGNAL(sig(const QString, const int)), this, SLOT(slot_main(const QString, const int)));m_sender-emitsig(thread, 220);}exec();
}main.cpp
#include QCoreApplication
#include QDebug
#include QThread
#include iostream
#include thread
#include QObject#include sender.h
#include recver.h
#include mythread.hint main(int argc, char *argv[])
{QCoreApplication a(argc, argv);qDebug() main thead id is : QThread::currentThreadId();//std::cout std::this_thread::get_id() std::endl;Sender sender;Mythread mythread(sender);mythread.start();return a.exec();
}运行效果如下 如上发送者对象在主线程创建在子线程中发送信号槽函数是在主线程中执行而并非在子线程中执行。