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

c++ qt--线程(二)(第九部分)

c++ qt–线程(二)(第九部分)

一.线程并发

1.并发问题:

​ 多个线程同时操作同一个资源(内存空间、文件句柄、网络句柄),可能会导致结果不一致的问题。发生的前提条件一定是多线程下共享资源

2.写一个有并发问题的例子

1.创建一个控制台窗口

在这里插入图片描述

2.在main.cpp的mian函数中写下面代码
    //创建3个线程,都走相同线程函数中HANDLE pun1=::CreateThread(nullptr,0,&fun,nullptr,0,nullptr);HANDLE pun2=::CreateThread(nullptr,0,&fun,nullptr,0,nullptr);HANDLE pun3=::CreateThread(nullptr,0,&fun,nullptr,0,nullptr);if(WaitForSingleObject(pun1,INFINITE/*一直等*/)==WAIT_OBJECT_0){//如果线程正常退出if(pun1){::CloseHandle(pun1);//关闭句柄,使用计数-1pun1=nullptr;}}if(WaitForSingleObject(pun2,INFINITE/*一直等*/)==WAIT_OBJECT_0){//如果线程正常退出if(pun2){::CloseHandle(pun1);//关闭句柄,使用计数-1pun2=nullptr;}}if(WaitForSingleObject(pun3,INFINITE/*一直等*/)==WAIT_OBJECT_0){//如果线程正常退出if(pun3){::CloseHandle(pun3);//关闭句柄,使用计数-1pun1=nullptr;}}qDebug()<<"-------------------count= "<<count;
3.在main.cpp中写下面代码
int count=0;//多个线程同时操作的变量
DWORD WINAPI fun (void *p){for(int i=0;i<100;i++){count++;qDebug()<<"count= "<<count;Sleep(50);}return 0;
}
4.分析结果

运行多次后,发现count变量最终的结果大多数不是300,而且输出count大多数会出现重复的值

这里是因为count++其实中间还分为几个阶段,当第一个线程存入值还没进行加操作,但是时间片结束了,这是就会到另一个线程,这里的count++是进行完整的,count存完并且加完了,然后再回到第一个线程,这时count进行加操作,这样就会出现count没加成功的情况,所以就会导致输出的count出现重复的值,count最终结果不是300

(三个线程一共执行了300次,正常count应该是300),这就是并发问题。

二.线程同步(解决并发问题)

1.线程同步的概念

线程同步就是通过协调线程执行的顺序,避免多个线程同时操作同一个资源导致并发问题,使多次执行结果一样

常见的线程同步方式:原子访问、关键段、时间、互斥量、条件变量、信号量

上面提到的并发问题,解决方法有很多,重点学习锁

2.原子访问

将上面代码进行修改

main.cpp的main函数中的代码不需要修改

对main.cpp中的其他需要修改的代码进行修改

int count=0;//多个线程同时操作的变量
DWORD WINAPI fun (void *p){for(int i=0;i<100;i++){::InterlockedIncrement((long*)&count);//此函数使把变量按照原子操作的形式进行自增操作(++),参数要求是long*,这里进行一个强转,//::InterlockedDecrement((long*)&count);//此函数使把变量按照原子操作的形式进行自减操作(--),参数要求是long*,这里进行一个强转,qDebug()<<"count= "<<count;Sleep(50);}
}

3.关键段

1.概念:

将一块代码段锁住,只有当进入这块代码段的线程走完这块代码段,其他线程才能进入该块代码段

2.将main.cpp中的需要修改的代码进行修改(用关键段去使线程同步)
CRITICAL_SECTION cs;//定义一个关键段变量DWORD WINAPI fun (void *p){for(int i=0;i<100;i++){::EnterCriticalSection(&cs);//进入关键段,加锁//实现的是这一段的代码锁住//------------count++;count2--;//-----------::LeaveCriticalSection(&cs);//离开关键段解锁qDebug()<<"count= "<<count;qDebug()<<"count2= "<<count2;Sleep(50);}
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);::InitializeCriticalSection(&cs);//关键段的初始化//进行输出看结果是否符合预期(如果没有关键段可能会出现重复的数,这里会导致count最终结果不会到达300,count2最终结果不会到达-300)HANDLE pun1=::CreateThread(nullptr,0,&fun,nullptr,0,nullptr);HANDLE pun2=::CreateThread(nullptr,0,&fun,nullptr,0,nullptr);HANDLE pun3=::CreateThread(nullptr,0,&fun,nullptr,0,nullptr);if(WaitForSingleObject(pun1,INFINITE/*一直等*/)==WAIT_OBJECT_0){if(pun1){::CloseHandle(pun1);pun1=nullptr;}}if(WaitForSingleObject(pun2,INFINITE/*一直等*/)==WAIT_OBJECT_0){if(pun2){::CloseHandle(pun1);pun2=nullptr;}}if(WaitForSingleObject(pun3,INFINITE/*一直等*/)==WAIT_OBJECT_0){if(pun3){::CloseHandle(pun3);pun1=nullptr;}}qDebug()<<"-------------------count= "<<count;qDebug()<<"-------------------count2= "<<count2;::DeleteCriticalSection(&cs);//关键段的删除return a.exec();
}
3.将关键段进行封装(优化)
封装成一个类
class my{
private:CRITICAL_SECTION cs;//定义一个关键段变量public:my(){::InitializeCriticalSection(&cs);}//构造函数中写关键段的初始化~my(){::DeleteCriticalSection(&cs);}//析构函数写关键段的删除void Lock(){//此函数写进入关键段的函数::EnterCriticalSection(&cs);//上锁}void UnLock(){//此函数写离开关键段的函数::LeaveCriticalSection(&cs);//解锁}} LOCK;//定义类对象DWORD WINAPI fun (void *p){for(int i=0;i<100;i++){LOCK.Lock();//进入关键段,加锁//实现的是这一段的代码锁住//------------count++;count2--;//-----------LOCK.UnLock();//离开关键段解锁qDebug()<<"count= "<<count;qDebug()<<"count2= "<<count2;Sleep(50);}
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);//进行输出看结果是否符合预期(如果没有关键段可能会出现重复的数,这里会导致count最终结果不会到达300,count2最终结果不会到达-300)HANDLE pun1=::CreateThread(nullptr,0,&fun,nullptr,0,nullptr);HANDLE pun2=::CreateThread(nullptr,0,&fun,nullptr,0,nullptr);HANDLE pun3=::CreateThread(nullptr,0,&fun,nullptr,0,nullptr);if(WaitForSingleObject(pun1,INFINITE/*一直等*/)==WAIT_OBJECT_0){if(pun1){::CloseHandle(pun1);pun1=nullptr;}}if(WaitForSingleObject(pun2,INFINITE/*一直等*/)==WAIT_OBJECT_0){if(pun2){::CloseHandle(pun1);pun2=nullptr;}}if(WaitForSingleObject(pun3,INFINITE/*一直等*/)==WAIT_OBJECT_0){if(pun3){::CloseHandle(pun3);pun1=nullptr;}}qDebug()<<"-------------------count= "<<count;qDebug()<<"-------------------count2= "<<count2;return a.exec();
}
4.用关键段优化之前单例代码中存在的问题
1.之前单例代码如下
#include <iostream>
using namespace std;
/*
1.当前类最多只能创建一个实例
2.当前这个唯一的实例,必须由当前类创建(自主创建),而不是调用者创建
3.必须向整个系统提供全局的访问点,来获取唯一的实例懒汉式:当第一次调用这个接口函数时,先创建单例					 时间换空间的做法
饿汉式:无论是否调用获取单例接口函数,都会提前创建单例				 空间换时间的做法*/class CSingleton {CSingleton(){}CSingleton(const CSingleton&) = delete;//弃用拷贝构造函数static CSingleton* m_spring;~CSingleton() {}
public:static struct DeleteSingleton {//保证申请的堆空间一定被回收~DeleteSingleton() {if(m_spring)delete m_spring;m_spring = nullptr;}} del;//静态对象,在程序结束时静态对象会自动被回收,然后就会调用析构函数,就一定能保证申请的堆空间被回收//有问题的代码,在多线程下,可能会创建多个对象static CSingleton* CreatCSingleton() {//加锁if (!m_spring) {//如果指针为空,则创建对象m_spring = new  CSingleton;}//解锁return m_spring;}static void DestoryCSingleton(CSingleton*& psin) {if (m_spring)delete m_spring;m_spring = nullptr;psin = nullptr;}};
CSingleton::DeleteSingleton CSingleton::del;//类外定义初始化, 格式: 类型 类名::静态变量名
CSingleton* CSingleton:: m_spring(nullptr);int main() {CSingleton* p1 = CSingleton::CreatCSingleton();CSingleton* p2 = CSingleton::CreatCSingleton();cout << p1 << "   " << p2 << endl;CSingleton::DestoryCSingleton(p1);return 0;
}
2.进行测试看是否会出现在多线程下,可能会创建多个对象的问题

将上面的代码修改为下面代码

#include <QCoreApplication>
#include <windows.h>
#include<QDebug>//1.当前类最多只能创建一个实例
//2.当前这个唯一的实例,必须由当前类创建(自主创建),而不是调用者创建
//3.必须向整个系统提供全局的访问点,来获取唯一的实例
//
//
//懒汉式:当第一次调用这个接口函数时,先创建单例					 时间换空间的做法
//饿汉式:无论是否调用获取单例接口函数,都会提前创建单例				 空间换时间的做法class CSingleton {CSingleton(){}CSingleton(const CSingleton&) = delete;//弃用拷贝构造函数static CSingleton* m_spring;~CSingleton() {}
public:static struct DeleteSingleton {//保证申请的堆空间一定被回收~DeleteSingleton() {if(m_spring)delete m_spring;m_spring = nullptr;}} del;//静态对象,在程序结束时静态对象会自动被回收,然后就会调用析构函数,就一定能保证申请的堆空间被回收static CSingleton* CreatCSingleton() {if (!m_spring) {//如果指针为空,则创建对象m_spring = new  CSingleton;}return m_spring;}static void DestoryCSingleton(CSingleton*& psin) {if (m_spring)delete m_spring;m_spring = nullptr;psin = nullptr;}};
CSingleton::DeleteSingleton CSingleton::del;//类外定义初始化, 格式: 类型 类名::静态变量名
CSingleton* CSingleton:: m_spring(nullptr);//下面的5行代码是用来测试是否会出现问题的
DWORD WINAPI pun(void* p){Sleep(100);CSingleton *t=CSingleton::CreatCSingleton();//创建单例qDebug()<<t;//输出地址看有没有不同的地址出现,以此来确认是否出现了问题
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);//下面的3行代码是用来测试是否会出现问题的for(int i=0;i<100;i++)::CreateThread(nullptr,0,&pun,nullptr,0,nullptr);Sleep(5000);return a.exec();
}
3.用关键段进行优化
#include <QCoreApplication>
#include <windows.h>
#include<QDebug>//1.当前类最多只能创建一个实例
//2.当前这个唯一的实例,必须由当前类创建(自主创建),而不是调用者创建
//3.必须向整个系统提供全局的访问点,来获取唯一的实例
//
//
//懒汉式:当第一次调用这个接口函数时,先创建单例					    时间换空间的做法
//饿汉式:无论是否调用获取单例接口函数,都会提前创建单例				 空间换时间的做法class my{
private:CRITICAL_SECTION cs;public:my(){::InitializeCriticalSection(&cs);}~my(){::DeleteCriticalSection(&cs);}void Lock(){::EnterCriticalSection(&cs);//上锁}void UnLock(){::LeaveCriticalSection(&cs);//解锁}} LOCK;class CSingleton {CSingleton(){}CSingleton(const CSingleton&) = delete;//弃用拷贝构造函数static CSingleton* m_spring;~CSingleton() {}
public:static struct DeleteSingleton {//保证申请的堆空间一定被回收~DeleteSingleton() {if(m_spring)delete m_spring;m_spring = nullptr;}} del;//静态对象,在程序结束时静态对象会自动被回收,然后就会调用析构函数,就一定能保证申请的堆空间被回收static CSingleton* CreatCSingleton() {//加锁LOCK.Lock();if (!m_spring) {//如果指针为空,则创建对象m_spring = new  CSingleton;}//解锁LOCK.UnLock();return m_spring;}static void DestoryCSingleton(CSingleton*& psin) {if (m_spring)delete m_spring;m_spring = nullptr;psin = nullptr;}};
CSingleton::DeleteSingleton CSingleton::del;//类外定义初始化, 格式: 类型 类名::静态变量名
CSingleton* CSingleton:: m_spring(nullptr);DWORD WINAPI pun(void* p){Sleep(100);CSingleton *t=CSingleton::CreatCSingleton();qDebug()<<t;}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);for(int i=0;i<100;i++){::CreateThread(nullptr,0,&pun,nullptr,0,nullptr);}Sleep(5000);return a.exec();
}
4.上面代码还有能够进行优化的地方(49-59行的代码可以继续进行优化)
#include <QCoreApplication>
#include <windows.h>
#include<QDebug>//1.当前类最多只能创建一个实例
//2.当前这个唯一的实例,必须由当前类创建(自主创建),而不是调用者创建
//3.必须向整个系统提供全局的访问点,来获取唯一的实例
//
//
//懒汉式:当第一次调用这个接口函数时,先创建单例					    时间换空间的做法
//饿汉式:无论是否调用获取单例接口函数,都会提前创建单例				 空间换时间的做法int count1;
class my{
private:CRITICAL_SECTION cs;public:my(){::InitializeCriticalSection(&cs);}~my(){::DeleteCriticalSection(&cs);}void Lock(){::EnterCriticalSection(&cs);//上锁}void UnLock(){::LeaveCriticalSection(&cs);//解锁}} LOCK;class CSingleton {CSingleton(){}CSingleton(const CSingleton&) = delete;//弃用拷贝构造函数static CSingleton* m_spring;~CSingleton() {}
public:static struct DeleteSingleton {//保证申请的堆空间一定被回收~DeleteSingleton() {if(m_spring)delete m_spring;m_spring = nullptr;}} del;//静态对象,在程序结束时静态对象会自动被回收,然后就会调用析构函数,就一定能保证申请的堆空间被回收static CSingleton* CreatCSingleton() {if (!m_spring){//如果不是空的就直接不进入上锁和解锁的流程,这样可以省时间(如果两个线程一个很快一个很慢,那慢的那个一定是非空的)//加锁LOCK.Lock();::InterlockedIncrement((long*)&count1);//这里用一个conut1变量来进行自增,看上锁和解锁的流程要进行多少次(如果没有此判断语句,那进入上锁和解锁的流程一共要100次,看能少进入上锁和解锁的流程多少次)if (!m_spring) {//如果指针为空,则创建对象m_spring = new  CSingleton;}//解锁LOCK.UnLock();}return m_spring;}static void DestoryCSingleton(CSingleton*& psin) {if (m_spring)delete m_spring;m_spring = nullptr;psin = nullptr;}};
CSingleton::DeleteSingleton CSingleton::del;//类外定义初始化, 格式: 类型 类名::静态变量名
CSingleton* CSingleton:: m_spring(nullptr);DWORD WINAPI pun(void* p){Sleep(100);CSingleton *t=CSingleton::CreatCSingleton();qDebug()<<t;}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);for(int i=0;i<100;i++){::CreateThread(nullptr,0,&pun,nullptr,0,nullptr);}Sleep(5000);qDebug()<<count1;//输出count1的值return a.exec();
}

三.用qt中的进度条组件和四个按钮组件实现线程的五大状态(用windowsAPI实现的)

1.创建一个窗口项目

在这里插入图片描述

2.添加所用的组件如下

在这里插入图片描述

这里还用到了栅格布局

3.将每个按键组件都用qt自带的创建槽函数功能创建槽函数

在这里插入图片描述

4.将每个按键的功能进行实现

1.mainwindow.h中的代码如下
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <windows.h>
#include "mythread.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_pushButton_3_clicked();void on_pushButton_clicked();void on_pushButton_4_clicked();void on_pushButton_2_clicked();void slots_setValue(int);//槽函数(用来对进度条进行操作的函数)signals://信号(用来发送对进度条进行操作的信号)void signals_setValue(int);private:Ui::MainWindow *ui;public:HANDLE pun;//将线程变成类成员函数,使其可以在类的成员函数间进行使用bool m_isQuit;//看线程是否退出public:Ui::MainWindow* getUI(){//公共接口,获取ui以对进度条组件创建的进度条对象进行修改return ui;}public:mythread m_thread;
};
#endif // MAINWINDOW_H
2.mainwindow.cpp中的代码如下
#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);m_Handle=nullptr;connect(this,SIGNAL(signals_setValue(int)),this,SLOT(slots_setValue(int)),Qt::QueuedConnection);//两个线程之间信号和槽的绑定需要用队列连接,不能直连
}MainWindow::~MainWindow()
{delete ui;//这里是防止没有进行结束操作,直接关闭了程序,导致线程没有正常结束,所以这里在程序结束时,看线程有没有被关闭,如果没有关闭那么关闭if(m_Handle){::CloseHandle(m_Handle);}m_Handle=nullptr;
}DWORD WINAPI fun(void *p){MainWindow* pun=( MainWindow*)p;int i=0;while(!pun->m_isQuit){//如果线程没有结束//pun->getUI()->progressBar->setValue(i);//这里发现此方法不好使(原因应该是因为有两个线程,信号和槽用了直连的方式,如果用队列连接的方式就不会有问题了,所以我们手动使用队列连接信号和槽,然后手动发射信号,用槽函数进行处理)//发射信号emit pun->signals_setValue(i);i=++i%101;Sleep(80);}return 0;
}void MainWindow::on_pushButton_3_clicked()//开始
{if(!m_Handle){m_isQuit=false;m_Handle=CreateThread(nullptr,0,&fun,this,0,nullptr);}}void MainWindow::on_pushButton_clicked()//暂停
{::SuspendThread(m_Handle);//挂起线程
}void MainWindow::on_pushButton_4_clicked()//恢复
{::ResumeThread(m_Handle);//恢复线程
}void MainWindow::on_pushButton_2_clicked()//退出
{m_isQuit=true;if(WaitForSingleObject(m_Handle,INFINITE)==WAIT_OBJECT_0){//如果线程退出了if(m_Handle){::CloseHandle(m_Handle);m_Handle=nullptr;}}}void MainWindow::slots_setValue(int i){//槽函数(用来对进度条进行操作的函数)ui->progressBar->setValue(i);
}

四.用qt中的进度条组件和四个按钮组件实现线程的五大状态(使用qt里自己封装的线程库实现的)

1.创建一个窗口项目

在这里插入图片描述

2.添加所用的组件如下

在这里插入图片描述

这里还用到了栅格布局

3.将每个按键组件都用qt自带的创建槽函数功能创建槽函数

在这里插入图片描述

4.将每个按键的功能进行实现

1.我们要使用qt里自己封装的线程库首先要新建一个类

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.给创建的类添加父类(线程类的父类),添加线程库的头文件

在这里插入图片描述

3.将创建的类进行完善
1.类的头文件的代码如下
#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QThread>
#include<windows.h>
class mythread : public QThread
{Q_OBJECT//如果用到了信号槽函数,那么需要这个宏
public:mythread();//构造函数~mythread();//析构函数
public:virtual void run();//虚函数,线程运行的函数CRITICAL_SECTION m_cs;//创建关键段(此关键段是为了在暂停的时候,循环也会因为关键段暂停,使其线程真正的暂停)public:bool m_isQuit;//用来判断线程函数是否退出的变量bool m_isPause;//用来判断线程函数是狗暂停的变量signals://信号函数void signals_emitData(int);//用来发射信号的函数
};#endif // MYTHREAD_H
2.类的源文件的代码如下
#include "mythread.h"
#include <QDebug>mythread::mythread():m_isQuit(false),m_isPause(false)//初始化
{::InitializeCriticalSection(&m_cs);//初始化关键段
}mythread::~mythread()
{::DeleteCriticalSection(&m_cs);//回收关键段
}//qt 封装的线程库中的线程函数
void mythread::run(){//将此函数进行重写int i=0;while(!m_isQuit){//判断是否退出if(m_isPause){//判断是否暂停qDebug()<<"暂停";EnterCriticalSection(&m_cs);//进入关键段LeaveCriticalSection(&m_cs);//离开关键段continue;}//发射信号emit signals_emitData(i);i=++i%101;this->msleep(80);}
}
4.mainwindow.h中的代码如下(比用windowsAPI实现的mainwindow.h代码多了一个类对象)

此代码是在mainwindow.h的MainWindow的类中写的

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <windows.h>
#include "mythread.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_pushButton_3_clicked();void on_pushButton_clicked();void on_pushButton_4_clicked();void on_pushButton_2_clicked();void slots_setValue(int);signals:void signals_setValue(int);private:Ui::MainWindow *ui;public:HANDLE m_Handle;bool m_isQuit;public:Ui::MainWindow* getUI(){return ui;}
//下面这两行就是多的
public:mythread m_thread;
};
#endif // MAINWINDOW_H
5.mainwindow.cpp中的代码如下
#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);m_Handle=nullptr;connect(this,SIGNAL(signals_setValue(int)),this,SLOT(slots_setValue(int)),Qt::QueuedConnection);//线程类库中的信号 和 slots_setValue做绑定链接connect(&m_thread,SIGNAL(signals_emitData(int)),this,SLOT(slots_setValue(int)),Qt::QueuedConnection);
}MainWindow::~MainWindow()
{delete ui;//这里是防止没有进行结束操作,直接关闭了程序,导致线程没有正常结束,所以这里在程序结束时,看线程有没有被关闭,如果没有关闭那么关闭if(m_Handle){::CloseHandle(m_Handle);}m_Handle=nullptr;
}DWORD WINAPI fun(void *p){MainWindow* pun=( MainWindow*)p;int i=0;while(!pun->m_isQuit){//发射信号emit pun->signals_setValue(i);i=++i%101;Sleep(80);}return 0;
}void MainWindow::on_pushButton_3_clicked()//开始
{m_thread.m_isQuit=false;//为了下一次创建新线程能正常执行所做的操作(如果不进行此操作,那么线程刚创建就被回收了)m_thread.start(); //启动线程,执行线程函数 run}void MainWindow::on_pushButton_clicked()//暂停
{::EnterCriticalSection(&m_thread.m_cs);//进入关键段(这里进入关键段之后,只有先离开关键段,才能再次进入关键段,以此来达到真正暂停的效果)m_thread.m_isPause=true;//暂停线程}void MainWindow::on_pushButton_4_clicked()//恢复
{m_thread.m_isPause=false;//恢复线程::LeaveCriticalSection(&m_thread.m_cs);//离开关键段
}void MainWindow::on_pushButton_2_clicked()//退出
{m_thread.m_isQuit=true;
}void MainWindow::slots_setValue(int i){//槽函数(用来对进度条进行操作的函数)ui->progressBar->setValue(i);
}

相关文章:

c++ qt--线程(二)(第九部分)

c qt–线程&#xff08;二&#xff09;&#xff08;第九部分&#xff09; 一.线程并发 1.并发问题&#xff1a; ​ 多个线程同时操作同一个资源&#xff08;内存空间、文件句柄、网络句柄&#xff09;&#xff0c;可能会导致结果不一致的问题。发生的前提条件一定是多线程下…...

​企业数据泄露不断,深信服EDR助企业构建数据“安全屋”

随着数字时代不断发展,数据泄露问题愈发严峻,个人信息安全面临着严重的威胁。近日,加拿大电信巨头加拿大贝尔(Bell Canada)对外披露了一起大规模数据泄露事件,该公司承认黑客入侵其系统,并窃取了190万个用户电子邮件地址以及约1700个用户姓名及活跃电话号码信息,相关损失无法估…...

单线复用iptv影响网速吗?

IPTV单线复用对网速有影响吗&#xff1f;这是一个比较常见的问题。如果你家的局域网是老的100M局域网LAN的路由器&#xff0c;走单线复用会影响你上网速度。但是如果你家的局域网是千兆网络&#xff0c;IPTV单线复用叠加上去的这点流量算不上什么&#xff0c;可以认为不占用网速…...

C语言中常用的字符串处理函数(strlen、strcpy、strcat、strcmp)

文章目录 写在前面1. strlen1.1 函数介绍1.2 模拟实现 2. strcpy2.1 函数介绍2.2 模拟实现 3. strcat3.1 函数介绍3.2 模拟实现 4. strcmp4.1 函数介绍4.2 模拟实现 写在前面 本篇文章介绍了C语言中常用的字符串处理函数&#xff0c;包括strlen、strcpy、strcat和strcmp。文章…...

Suricata – 入侵检测、预防和安全工具

一、Suricata介绍 Suricata是一个功能强大、用途广泛的开源威胁检测引擎&#xff0c;提供入侵检测 (IDS)、入侵防御 (IPS) 和网络安全监控功能。它执行深度数据包&#xff08;网络流量&#xff09;检查以及模式匹配&#xff0c;在威胁检测中非常强大。 工作流程&#xff1a; 主…...

vscode 乱码解决

windows 10 系统 vs code 编译运行和调试 C/C_vscode windows编译_雪的期许的博客-CSDN博客 VS Code默认文件编码时UTF-8&#xff0c;这对大多数情况是没有问题的&#xff0c;却偏偏对C/C有问题。如果以UTF-8编码保存C/C代码&#xff0c;那么只能输出英文&#xff0c;另外使用…...

SpringCloud(37):Spring Cloud Alibaba 综合集成架构演示

Spring Cloud是一个较为全面的微服务框架集,集成了如服务注册发现、配置中心、消息总线、负载均衡、断路器、API网关等功能实现。而在网上经常会发现Spring Cloud与阿里巴巴的Dubbo进行选择对比,这样做其实不是很妥当,前者是一套较为完整的架构方案,而Dubbo只是服务治理与R…...

【单片机】15-AD和DA转换

1.AD转换及其相关背景知识 1.基本概念 1.什么是AD转换&#xff1f; A&#xff08;A&#xff0c;analog&#xff0c;模拟的&#xff0c;D&#xff0c;digital&#xff0c;数字的&#xff09; 现实世界是模拟的&#xff0c;连续分布的&#xff0c;无法被分成有限份&#xff1b;…...

基于FPGA的I2C读写EEPROM

文章目录 前言一、I2C协议1.1 I2C协议简介1.2 物理层1.3 协议层 二、EEPROM2.1 型号及硬件规格2.2 各种读写时序 三、状态机设计四、项目源码&#xff1a;五、实现效果参考资料 前言 本次项目所用开发板FPGA芯片型号为&#xff1a;EP4CE6F17C8 EEPROM芯片型号为&#xff1a;24L…...

Viva Employee Communications Communities部署方案

目录 Viva Employee Communications & Communities产品介绍 1. 沟通中心(Communications Center) 2. 新闻和公告(News and Announcements)...

WPF向Avalonia迁移(三、项目结构)

前提&#xff1a; Avalonia版本11.0.0 1.配置文件 1.1 添加配置文件 1.2 读取配置文件 添加System.Configuration.ConfigurationManager using Avalonia.Controls; using System.Configuration;namespace AvaloniaApplication7.Views {public partial class MainWindow : W…...

cvpr24写作模板pdfLaTex编译器注意点小结

文章目录 1 更改作者显示 Anonymous CVPR submission2 \label标签3 换行符// 与换列符&4 \medskip5 首行缩进6 插入图片6.1 单幅图片6.2 并排显示\hfill Reference https://cvpr.thecvf.com/Conferences/2024 1 更改作者显示 Anonymous CVPR submission 这一行开头加上% …...

windows版php扩展包下载

php8有些扩展需自己下载&#xff0c;像redis 看下phpinfo中的PHP Extension Build&#xff0c;确定自己的php版本 windows.php.net - /downloads/pecl/releases/...

计算机竞赛 题目:基于深度学习的中文汉字识别 - 深度学习 卷积神经网络 机器视觉 OCR

文章目录 0 简介1 数据集合2 网络构建3 模型训练4 模型性能评估5 文字预测6 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的中文汉字识别 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &a…...

Django跨域访问 nginx转发 开源浏览器

Django跨域访问 https://blog.csdn.net/lonelysnowman/article/details/128086205 nginx转发 https://blog.csdn.net/faye0412/article/details/75200607/ 开源浏览器 https://www.oschina.net/p/chromiumengine 浏览器油猴开发 https://blog.csdn.net/mukes/article/detail…...

Docker Alist 在线网盘部署

文章目录 拉取镜像创建并运行查看容器自动生成的密码在浏览器中进行访问 挂载本地磁盘 拉取镜像 docker pull xhofe/alist-aria2创建并运行 # -v /data/alist:/opt/alist/data 挂载本地目录 docker run -d --restartalways -v /data/alist:/opt/alist/data -p 5244:5244 -e P…...

Jmeter吞吐量控制器使用小结

吞吐量控制器(Throughput Controller)场景: 在同一个线程组里, 有10个并发, 7个做A业务, 3个做B业务,要模拟这种场景,可以通过吞吐量模拟器来实现.。 添加吞吐量控制器 用法1: Percent Executions 在一个线程组内分别建立两个吞吐量控制器, 分别放业务A和业务B 吞吐量控制器采…...

3分钟轻松实现网关网口连接罗克韦尔AB CompactLogix系列PLC

目录 EG网关网口连接罗克韦尔AB CompactLogix系列PLC 一. 准备工作 1.1 在对接前我们需准备如下物品 1.2 EG20网关准备工作 1.3 PLC准备工作 二. EMCP平台设置 2.1 新增EG设备 2.2 远程配置网关 2.3 网关绑定 2.4 通讯参数设置 2.5 创建设备驱动 2.5.1 添加变量 2.…...

vscode刷leetcode使用Cookie登录

1、打开vscode&#xff0c;选择扩展&#xff0c;搜索leetcode&#xff0c;选择第一个&#xff0c;带有中文力扣字样&#xff0c;安装后重启 2、选择这个小球&#xff0c;切换中文版本&#xff0c;切换后&#xff0c;会显示一个打勾 3、选择小球旁边的有箭头的小门&#xff0…...

每次启动Docker容器指定IP、hosts和端口

每次启动Docker容器指定IP、hosts和端口 1问题描述1解决办法1.1启动容器指定好IP、hostname、端口等信息1.2通过docker-compose启动容器&#xff0c;可以配置extra_hosts属性1.3通过k8s来管理容器&#xff0c;则在可以在创建pod的yaml文件通过hostAliases添加域名IP映射 2问题描…...

PL/SQL增量同步

PL/SQL全量同步_枯河垂钓的博客-CSDN博客 目录 增量同步 增量同步存储过程 ORACEL 独有的 增量更新 merge into 增量同步 逻辑: 用源表的数据更新目标表,数据存在则更新,数据不存在,则插入 实现的逻辑: 1. 首先判断目标表是否有源表的数据 2. 如果有,则用源表的数据更新…...

C++——多态底层原理

虚函数表 先来看这个问题&#xff1a; class Base { public: virtual void Func1() { cout << "Func1()" << endl; } private: int _b 1; }; sizeof(Base)是多少&#xff1f; 答案是&#xff1a;8 因为Base中除了成员变量_b,还有一个虚函数表_vfp…...

asdTools-ReID热力图可视化

文章首发见博客&#xff1a;https://mwhls.top/4869.html。 无图/格式错误/后续更新请见首发页。 更多更新请到mwhls.top查看 欢迎留言提问或批评建议&#xff0c;私信不回。 Github - 开源代码及Readme Blog - 工具介绍 摘要&#xff1a;基于TorchCam实现ReID的热力图可视化的…...

CSS学习笔记

目录 1.CSS简介1.什么是CSS2.为什么使用CSS3.CSS作用 2.基本用法1.CSS语法2.CSS应用方式1. 内部样式2.行内样式3.外部样式1.使用 link标签 链接外部样式文件2.import 指令 导入外部样式文件3.使用举例 3.选择器1.基础选择器1.标签选择器2.类选择器3.ID选择器4.使用举例 2.复杂选…...

linux操作命令

VMware版本&#xff1a; 17.0 ubantu版本&#xff1a;22.04.3 命令&#xff1a; # 查看当前目录文件 ls# 切换路径 []内是路径 cd [snap/] cd ../ #返回上一层# 创建文件 []内是文件名 touch [test.txt]# 创建文件夹 []内是文件夹名 mkdir [myself]# 测试一下网络 ping www.b…...

猜数字游戏(Python)

一、猜数字游戏是一个古老的密码破译类、益智类小游戏&#xff0c;通常由两个人参与&#xff0c;一个人设置一个数字&#xff0c;一个人猜数字&#xff0c;当猜数字的人说出一个数字&#xff0c;由出数字的人告知是否猜中&#xff1a;若猜测的数字大于设置的数字&#xff0c;出…...

可视化模块

目录 可视化送入网络的图片可视化网络层的热力图 可视化送入网络的图片 送入的数据为imgs&#xff0c;其大小为(8,3,256,256)&#xff0c;并以2行8列进行展示 import matplotlib.pyplot as plt import numpy as np# 假设你的张量名为 tensor&#xff0c;形状为 (8, 3, 256, 2…...

MyBatis insert标签

<insert id"addWebsite" parameterType"string">insert into website(name)values(#{name}) </insert> 在 WebsiteMapper 接口中定义一个 add() 方法 public int addWebsite(String name); 参数为 Sting 类型的字符串&#xff1b;返回值为 …...

扬尘监测:智能化解决方案让生活更美好

随着工业化和城市化的快速发展&#xff0c;扬尘污染问题越来越受到人们的关注。扬尘不仅影响城市环境&#xff0c;还会对人们的健康造成威胁。为了解决这一问题&#xff0c;扬尘监测成为了一个重要的手段。本文将介绍扬尘监测的现状、重要性以及智能化解决方案&#xff0c;帮助…...

【AI视野·今日NLP 自然语言处理论文速览 第四十五期】Mon, 2 Oct 2023

AI视野今日CS.NLP 自然语言处理论文速览 Mon, 2 Oct 2023 Totally 44 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Efficient Streaming Language Models with Attention Sinks Authors Guangxuan Xiao, Yuandong Tian, Beidi C…...

三层架构做网站还是系统/百度seo优化软件

​使用Docker安装Tensorflow 对程序员来说在配置环境上花费大量时间&#xff0c;着实没有太大意义。遇到这篇文章以前您可能一个tensorflow环境配半天&#xff0c;各种错误出现&#xff0c;其他环境也一样。但是Docker为我们提供了解决方案&#xff0c;而且相比虚拟机来说&…...

wordpress插件域名限制/企业网站如何优化

原文链接&#xff1a;Generative Learning Algorithm in Chinese最新的版本在原文链接里可以找到。原博客会不断更新。这篇笔记主要梳理了吴恩达教授在斯坦福的CS229课程的内容&#xff0c;并结合了哥伦比亚大学几个教授相关笔记内容一并总结。请注意: 本文是翻译的一份学习资料…...

网站建设全包/青岛网络推广公司

16转换 10 进制&#xff1a; .toString("X"); 10转换 16 进制&#xff1a; .toString("X2");转载于:https://www.cnblogs.com/Iyce/archive/2012/11/15/2771627.html...

本地wordpress 外网访问不了/百度收录网址

前言从智能单品到全屋智能&#xff0c;随着消费者对生活品质追求的提升&#xff0c;智能化产品逐渐走入大众家庭&#xff0c;从而推动智能家居市场蓬勃发展。从 2017 年开始&#xff0c;智能家居设备已经应用于日常生活各项任务。2017 年其市场规模约为 4.3 亿美元。据 IDC 预测…...

阜宁做网站的公司/小红书怎么做关键词排名优化

当你打开任何一个朋友的微信朋友圈&#xff0c;首先映入眼帘的是什么呢?你可能会说是他的头像&#xff0c;但其实最吸睛的除了头像之外还有朋友圈的背景图。这块地方比头像的位置更为宽大&#xff0c;我们在这里可以充分发挥自己的想象力设计出适合自己的非常具有吸引力的朋友…...

博客网站 做淘宝客/百度云引擎搜索

https://blog.csdn.net/hutiewei2008/article/details/101202807         服务器通过笔记本电脑联网...