qt定时信号量_Qt基础开发之Qt多线程类QThread与Qt定时器类QTimer的详细方法与实例..._网易王三三的博客-程序员秘密

技术标签: qt定时信号量  

Qt多线程

我们之前的程序都是单线程运行,接下来我们开始引入多线程。就相当于以前的一个人在工作,现在多个人一起工作。

Qt中非常有必要使用多线程,这是因为,Qt应用是事件驱动型的,一旦某个事件处理函数处理时间过久,就会造成其它的事件得不到及时处理。

Qt中使用QThread来管理线程,一个QThread对象,就是一个线程。QThread对象也有消息循序exec()函数,用来处理自己这个线程的事件。

Qt实现多线程有两种方式

​1、Qt第一种创建线程方式

首先要继承QThread

重写虚函数QThread::run

[virtual protected] void QThread::run()

/*

* 基类QThread的run函数只是简单启动exec()消息循环

*/

例如:

#include

#include

#include

class MyThread : public QThread

{

public:

void run()

{

qDebug() << "QThread begin" << endl;

qDebug() << "child thread" << QThread::currentThreadId() << endl;

QThread::sleep(5);

qDebug() << "QThread end" << endl;

exec();

}

};

int main(int argc, char** argv)

{

QApplication app(argc, argv);

MyThread thread;

thread.start();

qDebug() << "main thread" << QThread::currentThreadId() << endl;

QThread::sleep(5);

qDebug() << "main thread" << QThread::currentThreadId() << endl;

thread.quit();

qDebug() << "main thread thread.quit()" << endl;

tread.wait();

qDebug() << "main thread thread.wait()" << endl;

return app.exec();

}

使用QThread的quit可以退出线程的消息循环,有时候不是马上退出,需要等到cpu的控制权交还给线程的exec()。

一般在子线程退出的时候需要主线程去回收资源,可以调用QThread的wait,等待子线程的退出,然后回收资源.

2、Qt第二种创建线程方式

继承 QObject

实例化一个QThread对象

实现槽函数.

QObject子类对象通过moveToThread将自己放到线程QThread对象中.

调用QThread对象的start函数启动线程

必须通过发射信号来让槽函数在线程中执行,发射的信号存放在线程exec()消息队列中。

例如:

mywork.h

#ifndef MYWORK_H

#define MYWORK_H

#include

#include

class MyWork : public QObject

{

Q_OBJECT

public slots:

void workSlot()

{

qDebug() << "QThread begin" << endl;

qDebug() << "child thread" << QThread::currentThreadId() << endl;

QThread::sleep(5);

qDebug() << "QThread end" << endl;

}

};

#endif // MYWORK_H

widget.cpp

#include

#include

#include

#include "mywork.h"

int main(int argc, char** argv)

{

qDebug() << "main thread" << QThread::currentThreadId() << endl;

QApplication app(argc, argv);

QThread thread;

MyWork work;

work.moveToThread(&thread);

QObject::connect(&thread, SIGNAL(started()), &work, SLOT(workSlot()));

thread.start();

QThread::sleep(6);

qDebug() << "thread is runing" << thread.isRunning() << endl;

thread.quit(); //调用quit让线程退出消息循环,否则线程一直在exec循环中

thread.wait(); //调用完quit后紧接着要调用wait来回收线程资源

qDebug() << "thread is runing" << thread.isRunning() << endl;

return app.exec();

}

需要特别注意的是:

线槽函数已经执行完进入线程exec()中,可以通过发射信号重新让槽函数在线程中执行。也可以通过quit()退出线程exec()。

QObject派生类对象,将要调用moveToThread,不能指定一个主线程父对象托管内存。

QWidget的对象及派生类对象都只能在GUI主线程运行,不能使用moveToThread移到子线程中,即使没有指定父对象。

多线程对象内存释放

既然QObject对象无法托管内存对象,那么到底是先释放线程对象,还是先释放这个QObject对象?

先把QObject在线程循环中释放(使用QObject::deleteLater函数),然后QThread::quit,然后QThread::wait。

例如:

​mywork.h

#ifndef MYWORK_H

#define MYWORK_H

#include

#include

class MyWork : public QObject

{

Q_OBJECT

public:

~MyWork() { qDebug() << __FUNCTION__ << endl; }

public slots:

void workSlot()

{

while(1)

{

qDebug() << "Work begin" << endl;

QThread::sleep(5);

qDebug() << "work end" << endl;

}

}

void otherWorkSlot()

{

qDebug() << "otherWork begin" << endl;

QThread::sleep(5);

qDebug() << "otherWork end" << endl;

}

};

#endif // MYWORK_H

widget.h

#ifndef WIDGET_H

#define WIDGET_H

#include

#include "mywork.h"

class Widget : public QWidget

{

Q_OBJECT

public:

Widget(QWidget *parent = 0);

~Widget();

private:

QThread *_thread;

MyWork * _myWork;

};

#endif // WIDGET_H

widget.cpp

#include "widget.h"

#include

#include "mywork.h"

#include

#include

Widget::Widget(QWidget *parent)

: QWidget(parent)

{

_myWork = new MyWork;

_thread = new QThread(this);

_myWork->moveToThread(_thread);

_thread->start();

QPushButton *pb0 = new QPushButton("work", this);

QPushButton *pb1 = new QPushButton("pb", this);

QHBoxLayout *hBox = new QHBoxLayout(this);

hBox->addWidget(pb0);

hBox->addWidget(pb1);

this->setLayout(hBox);

/*发射信号给在另外一个线程的对象的队列中*/

connect(pb0, SIGNAL(clicked()), _myWork, SLOT(workSlot()));

connect(pb1, SIGNAL(clicked()), _myWork, SLOT(otherWorkSlot()));

/*推荐用法释放内存*/

//connect(_thread, SIGNAL(finished()), _myWork, SLOT(deleteLater()));

}

Widget::~Widget()

{

_myWork->deleteLater(); //一定要在QThread线程退出之前

_thread->quit();

_thread->wait();

}

3、Qt线程的同步

​多线程在访问同时一个资源,(例如:多个线程可操作的变量、函数等),到底谁来使用这个资源是一个问题,就像一大群人去抢同一块蛋糕,可能其中一个人抢到,更有可能蛋糕被抢个稀烂。在多线程中,这个叫作竞争冒险。那么我们需要定一个规则来约束每一个人,比如:每个人排队来领蛋糕,这个在多线程中叫作同步方法。

​需要注意的是,同步不是同时,而是有序进行。

3.1、互斥锁

​Qt中的互斥锁是QMutex,不继承任何Qt基类,使用QMutex来锁共享资源,哪个线程抢到钥匙,哪个线程就有这个资源的使用权,其它线程等待这个线程使用完资源并归还钥匙,然后它们再去抢钥匙。

​例如:

QMutex mutex; //这对象一般定义在多个线程能访问的地方

mutex.lock(); //多个线程调用这个函数去获取锁,没有获取到的线程,将阻塞等待在这个函数上。

mutex.unlock(); //释放锁

QMutex::lock函数会让线程等待获取锁,如果不想等待,可以使用一下函数替换:

bool QMutex::tryLock(int timeout = 0)

/*

*参数 int timeout:等到timeout毫秒,不管有没获取到锁都返回,timeout为0时,直接返回。

*返回值 true代表获取到锁,false没有获取到

*/

有时候我们会忘记释放锁,Qt还为我们提供了管理锁的类QMutexLocker

QMutex mutex;

void func()

{

QMutexLocker locker(_mutex); //QMutexLocker最好实例化成栈对象,释放之前将QMutex解锁。

}

以上例子,一旦func()执行完成locker自动释放,释放之前先解锁。

3.2、信号量

​互斥锁保护的资源同一时刻只能有一个线程能够获取使用权,有些资源是可以限定多个线程同时访问,那么这个时候可以使用信号量。在Qt中信号量为QSemaphore。

QSemaphore sem(2) //初始化信号量为2

sem.acquire(); //信号量部位0的时候,调用这个函数会让信号量-1,一旦信号量为零,阻塞等待

semaphore.release(); //使信号量+1

4、Qt定时器QTimer

​定时器可以隔一段时间发出信号,通过接收这个信号来处理一些定时任务,需要注意的是,定时器并没有开启一个新线程。Qt中的定时器是QTimer继承自QObject。

通过QTimer::start()来启动定时器

void start(int msec)

/*

*定时msec毫秒后,发射timeout()信号

*/

通过链接信号timeout()来处理一些定时任务,例如:

#include "dialog.h"

#include

#include

Dialog::Dialog(QWidget *parent)

: QDialog(parent)

{

QTimer *timer = new QTimer(this);

connect(timer, SIGNAL(timeout()), this, SLOT(doSomeThing()));

timer->start(3000);

}

void Dialog::doSomeThing()

{

qDebug() << __FUNCTION__ << endl;

}

Dialog::~Dialog()

{

}

本文主要介绍了Qt多线程类QThread与Qt定时器类QTimer的详细方法与实例,更多关于Qt开发知识请查看下面的相关链接

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_34975747/article/details/113012677

智能推荐

linux进程同步与通信(共享内存和信号量)_a)一个程序(主线程)从客户端读入按键信息,一次将一行按键信息保存到一个缓冲区内_刘惜君的灯笼呐的博客-程序员秘密

1)  设计编写以下程序,着重考虑其同步问题:a)        一个程序(进程)从客户端读入按键信息,一次将“一整行”按键信息保存到一个共享存储的缓冲区内并等待读取进程将数据读走,不断重复上面的操作;b)       另一个程序(进程)生成两个进程,用于显示缓冲区内的信息,这两个进程并发读取缓冲区信息后将缓冲区清空(一个进程的两次显示操作之间可以加入适当的时延以便于观察)。c)

gre模考软件java.exe_GRE模考软件PP2注册下载方式_莫泽成的博客-程序员秘密

新东方留学生资料下载姓名手机号短信验证码图片验证码年级请选择5年级6年级7年级8年级9年级高一高二高三高三复习大一大二大三大四大五研一研二研三博一博二在职课程请选择雅思托福GREGMATSAT其他行政区请选择请选择请选择{"name":{"label":"姓名","placeholder":"","required":1,"formType":"text","group":"basics","na...

hdoj-1002-c++_hdoj1002 c++_qq_34364985的博客-程序员秘密

思路:用字符串来存储大整数,关键在于实现进位,可以先倒序(这样方便位数需要增加的情况)相加,然后再倒叙输出。结果:AC不附代码了,太懒没有写,直接贴别人的解法。https://blog.csdn.net/ironyoung/article/details/45420161...

net的Session配置_weixin_30751947的博客-程序员秘密

一.摘要所有Web程序都会使用Session保存数据. 使用独立的Session服务器可以解决负载均衡场景中的Session共享问题.本文介绍.NET平台下建立Session服务器的几种办法, 并介绍在使用Session时的各种经验和技巧.二.关于Session,SessionID和CookiesSession数据保存在服务器端, 但是每一个客户端都需要保存一个SessionID, S...

Mac无法开机?别着急看这里_喵小姐的鱼的博客-程序员秘密

台式机Mac或MacBook无法打开,或者可能无法通过Apple图标启动?不用担心,虽然会让人烦躁不安,但通常是可以修复的。以下就是重新启动Mac所需的所有步骤。只需按顺序进行操作即可,除非操作系统更新失败后Mac无法启动。在这种情况下可直接跳到步骤8。1.检查Mac是否有电源首先,检查你的Mac是否有插上电源。虽然这很愚蠢但却很明显,但是任何获得技术支持的人都知道,你必须首先解决这些明显的问题。因此,如果你的MacBook无法使用电池启动,电池可能已完全耗尽,或者可能发生故障了。如果你在连接电源

Opencv学习笔记 K-Means聚类算法_opencv 散点聚类_坐望云起的博客-程序员秘密

K-means算法是最为经典的基于划分的聚类方法,是十大经典数据挖掘算法之一。K-means算法的基本思想是:以空间中k个点为中心进行聚类,对最靠近他们的对象归类。通过迭代的方法,逐次更新各聚类中心的值,直至得到最好的聚类结果。 1、opencv版本的K-Means opencv中提供了完整的kmeans算法,其函数原型为: double kmeans( InputArray data, int K, InputOutputArray b...

随便推点

解决AD中pcb原件移动提示绿色报错问题_ad移动器件就报错_Utotao的博客-程序员秘密

有可能以下三个原因之一所导致的:1、不符合DRC规则,比如原件之间距离过近,就是报错2、右下角ROOM没有删除, 右键清楚就可以啦3、如果以上两个确证都是正常的,还是报错的话,终极解决方案:step1: 在pcb界面下,点击design-netlist-edit list,然后删除所有的网络标号;step2: design-class-component class ,然后右键下面列表...

细数 2020 年官方对 Android 的那些重大更新!_cym492224103的博客-程序员秘密

码个蛋(codeegg) 第 1088次推文不知不觉,2020 年也已接近尾声,今年虽然困难重重,但是 Android 社区的更新热情却并未消减 ,Google I/O 大会取消的同时...

css中块级元素的水平垂直居中问题_"<div class=\"outer\"> <div class=\"inner\"></div>_HTongi的博客-程序员秘密

为父元素添加绝对定位 position: absolute;为子元素添加绝对定位 position: absolute;子元素设置left right top bottom都置为0px子元素设置margin:auto;这里注意一定要加margin:auto; 这样才可以实现垂直水平居中// 两个简单的父子级块级元素示例 &lt;div class="outer"&gt; &lt;div class="inner"&gt;&lt;/div&gt; &lt;/div&gt;//..

程序员的简历到底该怎么写?_weixin_30788619的博客-程序员秘密

小明最近有换工作的打算,那身为程序员的我们,简历到底应该怎么写呢?我们知道,HR在筛选简历时主要从公司需求出发,重点不一,不过还是有很多“通用”的套路,为了在30秒内判断出这份简历是否值得跟进,我认为程序员写简历的正确姿势是这样的:主要风格即首次看到简历后的第一感觉。就好比小明多年相亲未遂,鼓起勇气参加“非诚勿扰”的节目,首次登场,台下的妹子看见他的第一眼,一定会有一个整体的Feel,他...

奋斗吧,程序员——第七章 学向勤中得,萤窗万卷书_学向勤中得萤窗万卷书常用于_yuanyun_elber的博客-程序员秘密

“水哥,过来帮下忙!”一箱办公用品快递到了,飞雪在门口叫道。飞雪的任务除了测试,还包括给大家请假填单子啦、帮大家领办公用品啦、开会发通知邮件啦,一个刚毕业的小姑娘,怪不容易的。“体力活?”水哥早从座位上弹了起来,又补充道,“我其实很忙的。”我也走到门口一起帮忙抬东西:“水哥,你体力可以的。”水哥看了看飞雪:“我体力好不好,飞雪知道的。”飞雪怒道:“elber,你看水哥又欺负我。

Linux系统调用--------wait() 与 waitpid()_wait nohung_沉西乐恩的博客-程序员秘密

waitpid系统调用在Linux函数库中的原型是:#include  #include pid_t waitpid(pid_t pid,int *status,int options)从本质上讲,系统调用waitpid和wait的作用是完全相同的,但waitpid多出了两个可由用户控制的参数pid和options,从而为我们编程提供了另一种更灵活的方式

推荐文章

热门文章

相关标签