QT中QTimer的循环时间与槽函数执行时间以及在事件循环中触发,不同时间的结果分析

目录

当循环时间小于槽函数时间时: 

当循环间隔时间大于槽函数时间时:

当存在两个定时器器,其中一个还是间隔100ms,另一个间隔1000ms: 

当两个定时器的循环周期大于槽函数执行时间时

当在主程序中添加一个for循环后 

当在for循环中加上人为触发其他事件QCoreApplication::processEvents() 后

当把for循环放到子线程中运行时 

当在子线程中定义定时器时 


在使用QT过程中,新手在QTimer,多线程,信号槽不是很了解的时候,常常容易感觉有点乱,最近自己编写了几个案例,仔细研究了一下定时器,多线程,信号槽之间的相互关系。

个人总结:

线程是程序运行的基本单位,GUI编程中,主线程既是GUI线程,其他都是子线程,在创建子线程时,个人还是建议用movethread的方式。这种方式能将整个对象的生命周期都放置到一个独立的子线程中,对象的所有操作都将在子线程中完成。很符合线程的概念。

线程之间优先采用信号槽的方式通讯。保证线程安全的同时,也能保证一些需要时序控制的过程的安全可控运行。省去了线程同步的麻烦。

信号槽之所以能省去线程同步的麻烦,正是因为事件循环的作用,信号发送到子线程后,将按发送先后的顺序依次插入到子线程的事件队列中,当前面的事件处理完成后,依次执行后续事件。这个方式就能起到线程同步的作用。

而通过movethread的创建的子线程,当start的时候,默认是会开启一个子线程的事件循环。在非直接连接的信号槽绑定后,所有的信号都将在子线程的事件循环中依次完成。

而定时器的运行,也是在线程的事件循环中实现的,当timeout信号发出后,在创建该定时器的线程中将触发对应槽函数。也即在哪个线程创建,对应的timeout就在哪个线程的事件循环中执行。

线程中的程序的执行是串行的,所以信号槽,定时器触发都是按其信号的发送时间来顺序执行。

正是因为这样,当有多个定时器时,对应的槽函数的执行时间就一定得注意了,最好不要超过定时器的设置时间,因为一旦超过,定时器设置的定时时间将不是自己所设定的定时周期执行。很重要。

但是当在子线程中执行while循环时,由于线程是串行工作,没有退出while时,将阻塞事件循环中的其他所有事件。这时需要好好考虑子线程的作用,以及需要完成的工作都有哪些,以及相关动作是否适合放置在1个子线程中,是否还需要再次创建子线程,都是需要考虑的。在while 中放置一个QCoreApplication::processEvents();来人为触发事件。可以在一些场景下,保证while循环运行同时,响应其他所有事件,但是其后也要跟一个sleep指令,并且时间要合适,才能保证其他事件的及时响应。个人建议不要小于10ms的sleep时间。

当循环时间小于槽函数时间时: 

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>

void timer1()
{
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;
    QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QTimer timeTest;
    timeTest.setTimerType(Qt::PreciseTimer);
    QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });
    
    timeTest.start(100);

    return a.exec();
}

执行结果: 

结果分析:

QTimer 设置的循环时间小于槽函数的执行时间时,当循环时间结束时,并不会将槽函数中断,而是等槽函数运行结束后,直接再次进入,中间没有间隔时间。

当循环间隔时间大于槽函数时间时:

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>

void timer1()
{
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;
    QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QTimer timeTest;
    timeTest.setTimerType(Qt::PreciseTimer);
    QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });
    
    timeTest.start(7000);

    return a.exec();
}

 结果分析:

间隔时间都比较准。每次的间隔时间也不会存在累计误差。

当存在两个定时器器,其中一个还是间隔100ms,另一个间隔1000ms: 

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>

void timer1()
{
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;
    QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}

void timer2()
{
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Timer2" << std::endl;
	//QThread::msleep(1000);
}
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QTimer timeTest,timeTest2;
    timeTest.setTimerType(Qt::PreciseTimer);
    timeTest2.setTimerType(Qt::PreciseTimer);
    QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });
    QObject::connect(&timeTest2, &QTimer::timeout, [=]() {timer2(); });

    timeTest.start(100);
    timeTest2.start(1000);
    return a.exec();
}

结果分析:

第一个100ms的定时器优先抢占触发事件,当执行完两个对应槽函数后,第二个1000ms的定时器才执行一次槽函数。 

100ms触发

1s-2s-3s-4s-5s-6s-1s-2s-3s-4s-5s-6s-第二个触发-

总结:在不能确定定时器槽函数执行时间时,如果还存在其他定时器,当第一个定时器执行超时时,将直接影响第二个定时器的执行周期。所以在这种应用中,尽量避免定时器的循环周期小于槽函数执行时长。

当两个定时器的循环周期大于槽函数执行时间时

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>

void timer1()
{
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;
    QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}

void timer2()
{
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Timer2" << std::endl;
	//QThread::msleep(1000);
}
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QTimer timeTest,timeTest2;
    timeTest.setTimerType(Qt::PreciseTimer);
    timeTest2.setTimerType(Qt::PreciseTimer);
    QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });
    QObject::connect(&timeTest2, &QTimer::timeout, [=]() {timer2(); });

    timeTest2.start(1000);
    timeTest.start(7000);
   
    return a.exec();
}

结果分析:

当两个定时器在同一个线程中时,两个定时器是按单线程串行的方式执行,当其中一个定时器触发时,必须等待当前定时器执行完成后,才有可能执行另外的定时器,两个定时器的优先级感觉是随机的。这也就解释了为什么上个案例定时周期不稳定的原因。

当在主程序中添加一个for循环后 

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>

void timer1()
{
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;
    QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}

void timer2()
{
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Timer2" << std::endl;
	//QThread::msleep(1000);
}
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QTimer timeTest,timeTest2;
    timeTest.setTimerType(Qt::PreciseTimer);
    timeTest2.setTimerType(Qt::PreciseTimer);
    QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });
    QObject::connect(&timeTest2, &QTimer::timeout, [=]() {timer2(); });

    timeTest2.start(1000);
    timeTest.start(7000);

    for (int i=0;i<100;++i)
    {
        std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Main"<<i << std::endl;
        QThread::msleep(100);
    }
   
    return a.exec();
}

结论:两个定时器必须在for循环执行完成后,才能触发。再次 证明定时器在主线程中是以串行的方式执行。 当for循环没有结束时,定时器的timeout信号在线程中是阻塞的状况,是无法响应对应槽函数的。

当在for循环中加上人为触发其他事件QCoreApplication::processEvents() 后

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>

void timer1()
{
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;
    QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}

void timer2()
{
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Timer2" << std::endl;
	//QThread::msleep(1000);
}
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QTimer timeTest,timeTest2;
    timeTest.setTimerType(Qt::PreciseTimer);
    timeTest2.setTimerType(Qt::PreciseTimer);
    QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });
    QObject::connect(&timeTest2, &QTimer::timeout, [=]() {timer2(); });

    timeTest2.start(1000);
    timeTest.start(7000);

    for (int i=0;i<100;++i)
    {
        std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Main"<<i << std::endl;
		//适当的位置,插入一个processEvents,保证事件循环被处理
		QCoreApplication::processEvents();
        QThread::msleep(100);
    }
   
    return a.exec();
}

结论:当添加了 QCoreApplication::processEvents();后 在每次的for循环中都触发一次进程事件,保证timeout事件触发,是可行的。

当把for循环放到子线程中运行时 

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>

void timer1()
{
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;
    QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}

void timer2()
{
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Timer2" << std::endl;
	//QThread::msleep(1000);
}

class TestThread1:public QThread
{

    //Q_OBJECT
public:
     TestThread1() {

    };
    ~TestThread1() {

    };

    void run()
    {
	   for (int i=0;i<1000;++i)
	  {
	      std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThread"<<i << std::endl;
		  //适当的位置,插入一个processEvents,保证事件循环被处理
		  //QCoreApplication::processEvents();
	      QThread::msleep(100);
	  }
    }


};


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QTimer timeTest,timeTest2;
    timeTest.setTimerType(Qt::PreciseTimer);
    timeTest2.setTimerType(Qt::PreciseTimer);
    QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });
    QObject::connect(&timeTest2, &QTimer::timeout, [=]() {timer2(); });

    timeTest2.start(1000);
    timeTest.start(7000);

    TestThread1* test1{nullptr};
    test1 = new TestThread1;
    test1->start();


  //  for (int i=0;i<100;++i)
  //  {
  //      std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Main"<<i << std::endl;
		适当的位置,插入一个processEvents,保证事件循环被处理
		//QCoreApplication::processEvents();
  //      QThread::msleep(100);
  //  }
   
    return a.exec();
}

 结论:当在子线程中运行时,两个定时器能正常按预想的方式运行

当在子线程中定义定时器时 

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>

void timer1()
{
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;
    QThread::msleep(1000);
    std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;
    QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}

void timer2()
{
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Timer2" << std::endl;
	//QThread::msleep(1000);
}

void timer3()
{
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThreadTime3_1" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThreadTime3_2" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThreadTime3_3" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThreadTime3_4" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThreadTime3_5" << std::endl;
	QThread::msleep(1000);
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThreadTime3_6" << std::endl;
}

void timer4()
{
	std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThreadTimer4" << std::endl;
	//QThread::msleep(1000);
}

class TestThread1:public QThread
{

    //Q_OBJECT
public:
     TestThread1() {

    };
    ~TestThread1() {

    };

    void run()
    {

        QTimer time3;
        QTimer time4;
		time3.setTimerType(Qt::PreciseTimer);
		time4.setTimerType(Qt::PreciseTimer);
		QObject::connect(&time3, &QTimer::timeout, [=]() {timer3(); });
		QObject::connect(&time4, &QTimer::timeout, [=]() {timer4(); });

		time3.start(1000);
		time4.start(7000);
	   for (int i=0;i<1000;++i)
	  {
	      std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThread"<<i << std::endl;
		  //适当的位置,插入一个processEvents,保证事件循环被处理
		  QCoreApplication::processEvents();
	      QThread::msleep(100);
	  }
    }


};


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QTimer timeTest,timeTest2;
    timeTest.setTimerType(Qt::PreciseTimer);
    timeTest2.setTimerType(Qt::PreciseTimer);
    QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });
    QObject::connect(&timeTest2, &QTimer::timeout, [=]() {timer2(); });

    timeTest2.start(1000);
    timeTest.start(7000);

    TestThread1* test1{nullptr};
    test1 = new TestThread1;
    test1->start();


  //  for (int i=0;i<100;++i)
  //  {
  //      std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Main"<<i << std::endl;
		适当的位置,插入一个processEvents,保证事件循环被处理
		//QCoreApplication::processEvents();
  //      QThread::msleep(100);
  //  }
   
    return a.exec();
}

结论:当在子线程中定义定时器时,现象跟在主线程的现象一致。 

QCoreApplication::processEvents();
          QThread::msleep(100); 这暂停很关键,不同的暂停时间,对其他事件的影响很大,如果没有这个暂停时间,:processEvents()将无效,暂停时间越短,其他事件执行的几率就越小。在实际的应用中需要是个合适的延时。

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值