当前位置: 首页 > news >正文

餐饮网站建设推广普通话手抄报内容大全

餐饮网站建设,推广普通话手抄报内容大全,怎么做网站兼容性测试,做电商有哪些网站文章目录一、多线程简介1. 基础知识2. 多线程的优缺点及注意事项二、多线程详解1. 背景案例2. 通过多线程对背景案例进行优化3. 方法一:多线程的创建使用(QT 4.7 以前)3.1 方法一的创建步骤3.2 方法一的具体实现及实现代码4. 方法二&#xff…

文章目录

  • 一、多线程简介
    • 1. 基础知识
    • 2. 多线程的优缺点及注意事项
  • 二、多线程详解
    • 1. 背景案例
    • 2. 通过多线程对背景案例进行优化
    • 3. 方法一:多线程的创建使用(QT 4.7 以前)
      • 3.1 方法一的创建步骤
      • 3.2 方法一的具体实现及实现代码
    • 4. 方法二:多线程的创建使用(QT 4.7 及以后)
      • 4.1 方法二的创建步骤
      • 4.2 方法二的具体实现
      • 4.3 方法二的实现代码

由于每次代码都是在原有程序上修改,因此除了新建项目,不然一般会在学完后统一展示代码。
提示:具体项目创建流程和注意事项见QT 学习笔记(一)
提示:具体项目准备工作和细节讲解见QT 学习笔记(二)

一、多线程简介

1. 基础知识

  • (1) 进程是操作系统结构的基础;是一个正在执行的程序;计算机中正在运行的程序实例;可以分配给处理器并由处理器执行的一个实体;由单一顺序的执行显示,一个当前状态和一组相关的系统资源所描述的活动单元。
  • (2) 线程是程序中一个单一的顺序控制流程。是程序执行流的最小单元。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
  • (3) 多线程是在单个程序中同时运行多个线程完成不同的工作。

2. 多线程的优缺点及注意事项

  • 通常情况下,应用程序都是在一个线程中执行操作。但是,当调用一个耗时操作(例如,大批量 I/O 或大量矩阵变换等 CPU 密集操作)时,用户界面常常会冻结。而使用多线程可以解决这一问题。
  • 多线程程序有以下几个优点:
  • (1) 提高应用程序响应速度。这对于图形界面开发的程序尤为重要,当一个操作耗时很长时,整个系统都会等待这个操作,程序就不能响应键盘、鼠标、菜单等操作,而使用多线程技术可将耗时长的操作置于一个新的线程,避免以上问题。
  • (2) 使多 CPU 系统更加有效。当前线程数不大于 CPU 数目时,操作系统可以调度不同的线程运行于不同的 CPU 上。
  • (3) 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为独立或半独立的运行部分,这样有利于代码的理解和维护。
  • (4) 和进程相比,线程是一种非常花销小,切换快的多任务操作方式。运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。
  • (5) 线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。
  • 多线程程序有以下几个缺点:
  • (1) 多线程程序的行为无法预期,当多次执行程序时,每一次的结果都可能不同。
  • (2) 多线程的执行顺序无法保证,它与操作系统的调度策略和线程优先级等因素有关。
  • (3) 多线程的切换可能发生在任何时刻、任何地点。
  • (4) 多线程对代码的敏感度高,对代码的细微修改都可能产生意想不到的结果。
  • 多线程使用过程中注意事项:
  • (1) 线程不能操作 ui 对象(从 QWidget 直接或间接派生的窗口对象)
  • (2) 需要移动到子线程中处理的模块类,创建的对象的时候不能指定父对象。

二、多线程详解

  • 生成一个新的项目,具体步骤过程见提示。
  • 在生成新项目的过程中,我们选择基类为 QWidget ,这是因为 QWidget 当中比较干净,不存在别的东西,而 QMainWindow 虽然也可以实现,但其中存在工具栏,菜单栏,核心控件等东西,比较复杂。

1. 背景案例

  • 在 QT 中使用 QThread 来管理线程。下面来看一个简单的例子:
  • 首先,我们在 ui 界面布置出所需要的窗口界面,包含一个 Display Widgets 当中的 LCD Number,并将其放大,这里需要注意的是,LCD Number 是有范围限定的,是 5 位,超过 5 位的数字就无法显示,一个按钮,用以启动 LCD Number。具体界面布局如下图所示。

在这里插入图片描述

  • 在整个过程当中,需要使用到定时器 QTimer。因此,先进行头文件的编写和变量的声明。在实现的过程当中不选择使用 Lambda 表达式,使用传统的槽函数(定时器的槽函数没有参数和返回值)进行功能的实现。
  • 定时器 QTimer 功能完成后,在程序界面对按钮进行转到槽函数操作,并通过按钮完成定时器 QTimer 的启动。
  • 当我们完成代码的编写后,点击启动按钮。此时,ui 界面会无法操作,LCD Number 没有任何变化,具体实现现象如下图所示。

在这里插入图片描述

  • 使用 QThread 中的 sleep 函数,让程序等待 5s,我们现在目前只有一个主线程,所以在点击按钮之后会造成定时器虽然设置了,但是 LCD Number 的显示数字是不会改变的,因为 sleep 了 5s 所以说需要等 5s 之后才会开始变化。
  • 如果 sleep 换成一个数据处理的函数时候,在数据处理函数执行的这段时间,其余的程序无法运行,会造成窗口卡住,无响应等问题,影响他人的正常使用。

2. 通过多线程对背景案例进行优化

  • 我们的主界面有一个用于显示时间的 LCD Number 数字面板还有一个用于启动任务的按钮。
  • 程序的目的是用户点击按钮,开始一个非常耗时的运算(程序中我们以程序界面睡眠 5s 来替代这个非常耗时的工作,在真实的程序中,这可能是一个网络访问,可能是需要复制一个很大的文件或者其它任务)。
  • 同时 LCD Number 开始显示逝去的毫秒数。毫秒数通过一个定时器 QTimer 进行更新。计算完成后,计时器停止。
  • 背景案例当中的是一个很简单的应用,也看不出有任何问题。但是当我们开始运行程序时,问题就来了:点击按钮之后,程序界面直接停止响应,直到结束后才开始重新更新。
  • 通过这个问题,我们决定这里使用多线程进行解决。这是因为 QT 中所有界面都是在 ui 线程中(也被称为主线程,就是执行了 QApplication::exec() 的线程),在这个线程中执行耗时的操作(,就会阻塞 ui 线程,从而让界面停止响应。
  • 所以,为了避免这一问题,我们要使用 QThread 开启一个新的线程。
  • 具体多线程的创建使用有如下两种方法。

3. 方法一:多线程的创建使用(QT 4.7 以前)

  • 方法一这里直接在背景案例的基础上进行修改。

3.1 方法一的创建步骤

在这里插入图片描述

  • (1) 自定义一个类,继承于 QThread,并且只有一个线程处理函数(和主线程不再同一个线程),这个线程处理函数就是重写父类中的 run 函数。
  • (2) 线程处理函数里面写入需要执行的复杂数据处理。
  • (3) 启动线程不能直接调用 run 函数,需要使用对象来调用 start 函数实现线程启动。
  • (4) 线程处理函数执行结束后可以定义一个信号来告诉主线程。
  • (5) 最后关闭线程。

3.2 方法一的具体实现及实现代码

  • 这里我们对背景案例进行优化,由多线程的创建步骤可知,需要添加一个 C++ 文件和类。

在这里插入图片描述

  • 基类选择 QObject,这里注意千万不要选成 QWidget,因为我们的线程并不是控件。

在这里插入图片描述

  • 在新建完成后,由于我们是要新建一个线程,也就是 QThread。在此,我们对刚刚生成的 QObject 进行修改,将其改为 QThread
  • 由于线程号是有限的,因此当我们使用完线程号后要及时关闭线程。
  • 在完成上述准备工作和代码编写后,具体实现现象和实现代码如下所示
  • (1) 实现现象
  • 按下按钮 start 后,开始计时,至于为什么是在 45 的时候停止的,是由于中间过程启动时间导致的。

在这里插入图片描述

  • 在完成计时后,输出 it is over。

在这里插入图片描述

  • (2) 主窗口头文件 widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTimer> //定时器头文件
#include "mythread.h" //线程头文件namespace Ui {
class Widget;
}class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = nullptr);~Widget();void dealtimeout(); //定时器槽函数void dealDone(); //线程结束槽函数void stopthread(); //停止线程槽函数private slots:void on_pushButton_clicked();private:Ui::Widget *ui;QTimer *mytimer; //声明变量mythread *thread; //线程对象
};#endif // WIDGET_H
  • (3) 主窗口源文件 widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QThread>
#include <QDebug>Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);mytimer = new QTimer(this);//只要定时器启动,自动触发timeout信号connect(mytimer,&QTimer::timeout,this,&Widget::dealtimeout);//分配空间,指定父对象thread = new mythread(this);connect(thread,&mythread::isDone,this,&Widget::dealDone);//当按窗口右上角关闭按钮X时,窗口触发destroyed()信号connect(this,&mythread::destroyed,this,&Widget::stopthread);
}void Widget::stopthread()
{//停止线程thread->quit();//等待线程完成当前工作thread->wait();
}void Widget::dealDone()
{qDebug() << "it is over";mytimer->stop(); //关闭定时器
}void Widget::dealtimeout()
{static int i = 0;i++;//设定LCD的值ui->lcdNumber->display(i);}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{if(mytimer->isActive() == false){//如果定时器没有工作mytimer->start(100);}//启动线程,处理数据thread->start();
}
  • (4) 子线程头文件 mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QThread>//自定义一个类重写线程处理函数
class mythread : public QThread
{Q_OBJECT
public:explicit mythread(QObject *parent = nullptr);protected://QThread的虚函数//线程处理函数//不能直接调用,通过start间接调用void run();signals://自定义一个线程处理函数指向完成后的一个信号void isDone();public slots:
};#endif // MYTHREAD_H
  • (5) 子线程源文件 mythread.cpp
#include "mythread.h"mythread::mythread(QObject *parent) : QThread(parent)
{}void mythread::run()
{//非常复杂的数据处理//需要耗时5sQThread::sleep(5);emit isDone();
}

4. 方法二:多线程的创建使用(QT 4.7 及以后)

  • 生成一个新的项目,具体步骤过程见提示。
  • 在生成新项目的过程中,我们选择基类为 QWidget ,这是因为 QWidget 当中比较干净,不存在别的东西,而 QMainWindow 虽然也可以实现,但其中存在工具栏,菜单栏,核心控件等东西,比较复杂。
  • 此方法比方法一更为复杂一些。

4.1 方法二的创建步骤

在这里插入图片描述

  • (1) 自定义一个类,只需要继承 QObject 即可,并且线程处理函数名字随便取,但是也只有一个线程处理函数。
  • (2) 创建一个自定义线程类的对象,不能指定父对象。
  • (3) 创建一个 QThread 类的对象,可以指定父对象。
  • (4) 将自定义线程对象加入到 QThread 类的对象,使用。
  • (5) 启动线程的时候要注意:启动 QThread 类的对象线程,调用 start 函数只是启动了线程,但是没有开启线程处理函数,线程处理函数的开启需要用到信号槽机制。
  • (6) 关闭线程。

4.2 方法二的具体实现

  • 其主要特点就是利用 QT 的事件驱动特性,将需要在次线程中处理的业务放在独立的模块(类)中,由主线程创建完该对象后,将其移交给指定的线程,且可以将多个类似的对象移交给同一个线程。
  • 首先,我们在 ui 界面布置出所需要的窗口界面,包含一个 Display Widgets 当中的 LCD Number,并将其放大,两个按钮,用以启动和停止 LCD Number。具体界面布局如下图所示。

在这里插入图片描述

  • 这里我们对背景案例进行优化,由多线程的创建步骤可知,需要添加一个 C++ 文件和类。

在这里插入图片描述

  • 基类选择 QObject,这里注意千万不要选成 QWidget,因为我们的线程并不是控件。

在这里插入图片描述

  • 在新建完成后,不同于方法一,它本身就是继承父类,因此,不需要将 QObject 修改为 QThread
  • 由于线程号是有限的,因此当我们使用完线程号后要及时关闭线程。
  • 如果我们要是有信号和槽,必须有如下图所示的宏。

在这里插入图片描述

  • 我们每隔 1s 发送一个信号,通过设置一个 while(1) 死循环,在其中调用 QThreadsleep 函数,每睡眠 1s 之后调用信号,如此往复。
  • 然后,在 ui 界面通过按钮 start 进行转到槽操作,启动定时器,由于我们每隔 1s 钟会发送一个信号,因此我们对这些信号进行处理,表明定时器已经正常启动。
  • 这里需要注意的是不能直接调用线程处理函数,直接调用线程处理函数会导致,线程处理函数和主线程在同一个线程。
  • start() 函数只是启动了线程,但是没有开启线程处理函数,线程处理函数的开启需要用到信号槽机制。
  • 完成启动定时器按钮的编写后,运行程序,点击按钮 start,每隔 1s 定时器计数加一,同时发送一个子线程号,具体实现现象如下图所示。

在这里插入图片描述

  • 然后,在 ui 界面通过按钮 close 进行转到槽操作,停止定时器,并回收线程资源(线程号是有限的)。
  • 正常的关闭线程是使用 quit() 函数,但该函数比较温柔,会让线程先完成当前工作再停止,由于我们这里是 while(1) 的死循环,因此,这种关闭线程的方法是不可取的。
  • 完成关闭定时器按钮的编写后,运行程序,当我们点击按钮 close 后,定时器会立刻停止工作,同时子线程号也不再发送,具体实现现象如下图所示。

在这里插入图片描述

  • 此时,当我们关闭 ui 界面时,会出现 QThread: Destroyed while thread is still running,表明我们的线程仍在继续工作,因此,我们通过信号和槽函数对这种现象进行修改。
  • 知识点补充:关于 QObject 类的 connect函数第五个参数(只在多线程当中才有意义),连接类型有自动,直接和队列三种。
  • (1) 自动连接(AutoConnection),默认的连接方式。
  • 如果信号与槽,也就是发送者与接受者在同一线程,等同于直接连接;
  • 如果发送者与接受者处在不同线程,等同于队列连接。
  • (2) 直接连接(DirectConnection)
  • 当信号发射时,槽函数立即直接调用。
  • 无论槽函数所属对象在哪个线程,槽函数总在发送者所在线程执行。
  • (3) 队列连接(QueuedConnection)
    当控制权回到接受者所在线程的事件循环时,槽函数被调用。槽函数在接受者所在线程执行。
  • 知识点补充:总结如下。
  • 队列连接:槽函数在接受者所在线程执行。
  • 直接连接:槽函数在发送者所在线程执行。
  • 自动连接:二者不在同一线程时,等同于队列连接

4.3 方法二的实现代码

  • (1) 主窗口头文件 widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QThread>
#include "mythread.h"namespace Ui {
class Widget;
}class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = nullptr);~Widget();void dealsignal(); //处理信号槽函数signals:void startthread(); //启动子线程的信号void dealclose();private slots:void on_pushButtonstart_clicked();void on_pushButton_2_clicked();private:Ui::Widget *ui;    mythread *myt;    QThread *thread;
};#endif // WIDGET_H
  • (2) 主窗口源文件 widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);//动态分配空间,不能指定父对象myt = new mythread;//创建子线程,指定父对象thread = new QThread(this);//把自定义的线程加入到子线程中myt->moveToThread(thread);connect(myt,&mythread::mysignal,this,&Widget::dealsignal);qDebug() << "主线程号:" << QThread::currentThread();connect(this,&Widget::startthread,myt,&mythread::mytimeout);connect(this,&Widget::destroyed,this,&Widget::dealclose);//线程处理函数内部,不允许操作图形界面
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButtonstart_clicked()
{if(thread->isRunning() == true){return;}//启动线程,但是没有启动线程处理函数thread->start();myt->setflag(false);//不能直接调用线程处理函数//直接调用线程处理函数会导致,线程处理函数和主线程在同一个线程//只能通过 signal - slot 方式调用emit startthread();
}void Widget::dealsignal()
{static int i = 0;i++;ui->lcdNumber->display(i);
}void Widget::on_pushButton_2_clicked()
{if(thread->isRunning() == false){return;}myt->setflag(true);thread->quit();thread->wait();
}void Widget::dealclose()
{myt->setflag(true);thread->quit();thread->wait();   
}
  • (3) 子线程头文件 mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QObject>class mythread : public QObject
{Q_OBJECT
public:explicit mythread(QObject *parent = nullptr);//线程处理函数void mytimeout();void setflag(bool flag = true); //isstop函数的外部接口signals:void mysignal();public slots:private:bool isstop;
};#endif // MYTHREAD_H
  • (4) 子线程源文件 mythread.cpp
#include "mythread.h"
#include <QThread>
#include <QDebug>mythread::mythread(QObject *parent) : QObject(parent)
{isstop = false;
}void mythread::mytimeout()
{while(isstop == false){QThread::sleep(1);emit mysignal();qDebug() << "子线程号:" << QThread::currentThread();if(true == isstop){break;}}
}void mythread::setflag(bool flag)
{isstop = flag;
}
http://www.cadmedia.cn/news/13366.html

相关文章:

  • 织梦网站版权足球排名最新排名世界
  • 网站建设方案实施关键词优化的建议
  • 没有建设的网站不能申请微信支付吗bt蚂蚁磁力
  • 企业网站优化广场舞父母不求咋报答百度做广告怎么收费
  • wordpress获取文章浏览次数搜索引擎优化原理
  • asp网站改php网站方法今日的重大新闻
  • 网站建设服务费如何做会计分录考研培训班集训营
  • 光谷网站制作百度统计登录
  • 内蒙古建设厅网站官网营销方式有哪几种
  • 网站在线客服系统哪个好北京搜索关键词优化
  • 化妆品商城网站建设开发策划方案最佳bt磁力搜索引擎
  • 南通网站建设苏鹏网络pc网站优化排名
  • 网站建设制作介绍河南百度官方网站登录
  • php 可以自己做网站吗企业门户网站模板
  • 沈阳网站营销福建seo排名
  • 大数据政府网站建设广州百度seo优化排名
  • 深圳做营销网站公司简介1元购买域名
  • 富阳区建设工程质监站网站网络小说网站三巨头
  • 最新域名解析网站行业关键词搜索量排名
  • 网站建设标书范本竞价排名适合百度这样的网络平台吗
  • 宣传推广的形式有哪些浑江区关键词seo排名优化
  • 网站建设中 html模板seo网站优化技术
  • 洛阳网站seo国际新闻头条今日要闻
  • 湘潭商城网站建设定制百度旗下产品
  • 县级政府网站建设方案深圳知名seo公司
  • 做网站中心陕西seo
  • 住房城乡建设部网站通报进入百度app
  • 论文网站建设的参考文献百度不能搜的十大禁词
  • 重庆网站有哪些搜索引擎优化工具
  • 网站建设功能需求文档合肥seo推广公司