当前位置: 首页 > 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问题描…...

别再手动描边了!用AutoCAD 2022画好异形PCB板框,一键导入Cadence SPB17.4

高效绘制异形PCB板框&#xff1a;AutoCAD与Cadence的无缝协作指南 在硬件设计领域&#xff0c;异形PCB板框的绘制一直是工程师们面临的挑战。传统矩形板框的绘制相对简单&#xff0c;但当项目需求涉及圆弧、缺口或不规则轮廓时&#xff0c;直接在Cadence Allegro中操作往往效率…...

从零部署noVNC:一次完整的远程桌面服务搭建与排错实录

1. 为什么选择noVNC&#xff1f; 最近在帮朋友部署远程桌面服务时&#xff0c;发现很多传统VNC方案都需要安装客户端&#xff0c;操作复杂不说&#xff0c;兼容性还差。直到发现了noVNC这个神器&#xff0c;它直接用浏览器就能访问远程桌面&#xff0c;彻底解决了跨平台访问的痛…...

Docker部署RabbitMQ后,你的admin账号真的能连上吗?一个权限配置的深度踩坑实录

Docker部署RabbitMQ后admin账号连接失败的深度排查指南 当你用Docker快速部署了RabbitMQ&#xff0c;创建了admin用户&#xff0c;甚至能通过Web界面登录&#xff0c;却在代码中遭遇ACCESS_REFUSED错误时&#xff0c;那种挫败感我深有体会。这不是简单的密码错误问题&#xff0…...

GPT-5.5推理效率优化背后的5个核心技术突破

概要GPT-5.5是OpenAI于2026年4月23日发布的旗舰模型&#xff0c;代号"Spud"。最近在库拉&#xff08;c.877ai.cn&#xff09;AI工具聚合平台上做了集中测试&#xff0c;GPT-5.5的推理效率提升不是单一优化的结果&#xff0c;而是五个核心技术方向同时突破。从数据看&…...

收藏!AI时代程序员是消失还是逆袭?小白程序员必看大模型逆袭指南

收藏&#xff01;AI时代程序员是消失还是逆袭&#xff1f;小白程序员必看大模型逆袭指南 文章探讨了AI对程序员行业的影响&#xff0c;指出AI抢走了程序员一半的饭碗&#xff0c;但也为另一半人打开了高阶职场的大门。初级岗位因AI工具普及而面临失业风险&#xff0c;但高级技术…...

PIM架构如何优化LLM推理中的内存墙问题

1. PIM架构核心原理与LLM推理瓶颈在传统冯诺依曼架构中&#xff0c;数据需要在处理器和内存之间频繁搬运&#xff0c;这种"内存墙"问题在大型语言模型(LLM)推理场景中尤为突出。处理内存计算(PIM)技术的革命性在于将计算单元直接嵌入内存控制器附近&#xff0c;通过近…...

手机号查QQ号终极指南:3分钟掌握Python逆向查询技巧

手机号查QQ号终极指南&#xff1a;3分钟掌握Python逆向查询技巧 【免费下载链接】phone2qq 项目地址: https://gitcode.com/gh_mirrors/ph/phone2qq 你是否曾需要快速验证手机号与QQ号的绑定关系&#xff1f;手机号查QQ号工具是一个简单高效的Python开源项目&#xff0…...

AI编程工具的内卷:Copilot、Cursor、通义灵码,谁能笑到最后?

当“内卷”的风吹到AI编程工具2026年&#xff0c;AI编程工具已不再是新鲜事物&#xff0c;而是开发者工具箱中的标配。从最初的代码补全&#xff0c;到如今的全栈智能体&#xff0c;这个赛道正经历着一场前所未有的“内卷”。GitHub Copilot、Cursor、通义灵码三足鼎立&#xf…...

GPU资源利用率监测与优化实战指南

1. GPU资源利用率监测基础解析在超算中心和AI训练集群中&#xff0c;GPU资源利用率&#xff08;GPU_UTIL&#xff09;是衡量计算效率的核心指标。这个看似简单的百分比背后&#xff0c;实际上反映了GPU内部多个执行单元的综合活跃状态。通过NVIDIA的DCGM&#xff08;Data Cente…...

如何使用日志实现业务全链路追踪

在现代分布式系统架构中&#xff0c;一个业务请求往往需要经过多个服务节点的协同处理&#xff0c;涉及网关、微服务、数据库、缓存、消息队列等多个组件。传统的日志记录方式通常局限于单个服务或模块&#xff0c;难以还原一个完整请求的流转路径&#xff0c;给问题排查、性能…...