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

Linux·进程控制(system V)

1. 共享内存        

        system V共享内存是最快的IPC形式,之前的管道是基于Linux内核开发的通讯方案,其读写接口都是现成的,因此内核设计者为了完成进程间通讯任务并不需要新增太多代码。而共享内存属于system V标准,是操作系统单独设计的一种通讯方案。

        简单来说,共享内存的实现形式和动态库很像,也是在物理内存中开辟一块空间,通过页表映射到两个不同的进程中,此时两个进程就能通过虚拟地址空间寻到同一块资源了。

        共享内存交给页表映射虚拟地址的操作叫做,将共享内存挂接到进程地址空间中。如果不用共享内存了,就把页表中的映射关系删除,这步操作叫去关联,当所有进程都与这块共享内存去关联之后,就可以把这块内存释放了。

        共享内存在任何时刻可以在OS中存在很多个,因此OS要先描述再组织,把共享内存们管理起来。

                        

        shmget()创建共享内存的函数。

        第一个参数key表示共享内存的唯一标识符,后面我们再说它

        第二个参数size表示创建共享内存块的大小。

        第三个参数shmflg有很多选项,我们就关注两个 IPC_CREAT IPC_EXCL

         IPC_CREAT:单独使用,如果共享内存块shm不存在就创建它,如果存在就获取它并返回

        IPC_EXCL:单独使用无意义,只有 IPC_CREAT | IPC_EXCL 如此将两个选项组合在一起如果shm不存在就创建它,如果存在就出错返回。

        这两个选项,第一个选项的作用是保证进程能拿到共享内存,第二个选项是标识不拿老的共享内存。

        返回值,成功返回shmid共享内存面向用户的标识符,如果创建失败返回-1

        key是函数参数,也就是要用户自己设定的,之所以不让系统设置因为如果系统能设置,岂不是系统自己就能有通讯方案了,再一个共享内存空间是A进程创建的,B进程与A进程之间是独立的,即使key可以由系统自己设置,B进程也无法得知A进程创建的共享内存空间的key。

        如果让用户来创建key值,那么在全局范围如果能把key值创建成功,说明就能同时让AB进程拿到key值的同时,保证这个key值对应的共享内存块是唯一的。

        在理论上key值可以由用户任意设置,但是有可能会出现该key值与现有key值冲突的情况,那共享内存就创建失败了,此时程序员就要手动修改key值,说白了这个key值就是一个一个碰出来的。因此虽然这个key值需要程序员去设置,但是不希望由程序员去生成,因此我们退出ftok()函数来生成这个唯一码。

        ftok()函数

                

        这个函数可以把字符串和数字通过特定算法整合,生成一个尽量的唯一值。第一个参数我们可以选择一个AB进程的公共路径,第二个参数选择项目id

        如果生成成功了,就会返回一个合法内存标识符

                

        此时我们让server进程创建共享内存空间

                        

        但是我们发现第一次运行server进程,成功创建了共享内存空间,但是后面就不能正确创建了。

        这是因为今天这个共享内存看起来是由进程创建的,但是实际上我们是用系统调用shmget()申请的内存空间,而这块空间会被认为成操作系统申请的,借了进程的手创建的,因此这块空间并不会随进程的结束而释放,而是随操作系统的退出而释放。

        共享内存的声明周期:随内核。要么用户要求OS释放,要么操作系统重启。

1.2 共享内存的管理指令

        查看共享内存 ipcs -m 指令

        

        如果只用ipcs指令会把消息队列,共享内存,信号量全打出来,选项-m可以筛选处共享内存。

        这里我们也可以看到我们刚刚创建的共享内存nattch表示当前多少进程相关,目前没有挂机就没有。

        

        删除共享内存 ipcrm -m (shmid) 命令

        shmid和key的区别,shmid是只给用户用的一个标识shm的标识符,key只作为内核中区分shm唯一性的标识符,不作为用户管理shm的id值。

        perms 表示共享内存的权限

        bytes 表示共享内存的大小,操作系统会以块为单元为用户申请空间,也就是单次最小申请4KB但如果用户代码中要求4097个字节,第二页中用户就只能使用1个字节,也就是操作系统虽然申请的第二个4KB但是只让用户用一个字节。

        

        代码删除共享内存 man shmctl 查看

                

        这个函数集成了对于共享内存的删改查等操作功能。

        第一个参数shmid不用说了,指定某个共享内存

        第二个参数 cmd 是选择操作方案,删除就选 IPC_RMID ,如果是删除就可以不要第三个参数。

        shmat()函数,把共享内存挂接到进程自己的地址空间上

                

        第一个参数shmid,共享内存面向用户的唯一标识符

        第二个参数shmaddr,可以由用户指定将共享内存挂接到虚拟地址的什么位置,不过我们不用管它,直接设置成nullptr就可以了

        第三个参数shmflg,可以选择共享内存的读写方案,不过暂时也不用管,只用共享内存通讯的话直接设置为 0 就可以

        返回值,挂接成功返回共享内存在虚拟地址空间中的起始地址,如果挂接失败返回-1并设置错误码,这个返回值很像malloc的返回值。

                         

                

        如果这样直接挂接的话就会发现是挂不上的,这个函数的返回是-1,这是因为共享内存空间也是有权限限制的。共享内存也是文件,它在底层原理上和文件系统极像,只是在操作方式上有所不同。

        ​​​​​​​        ​​​​​​​        ​​​​​​​        

        ​​​​​​​        ​​​​​​​                

        设置权限就是在创建共享内存的时候床架就好了。

        shmdt() 函数,共享内存去关联

        ​​​​​​​        ​​​​​​​        ​​​​​​​        

        参数就是刚才 shmat() 函数的返回值

        ​​​​​​​        

        去关联并不是删除,而是取消挂接,共享内存还在,如果想删除共享内存还是要用shmctl(IPC_RMID)

        最后我们可以写出这样一个关于共享内存操作的类

        ​​​​​​​        ​​​​​​​        

        

1.3 共享内存的通讯

        使用共享内存通讯不需要像管道那样使用系统调用,直接用地址向内存块中读写数据就好了。

        共享内存是所有进程间通讯方法中,速度最快的方案。

        共享内存在真正意义上使两个进程共享了资源,但是也没有加任何保护,进程对共享内存的读写不会互相阻塞等待,读完数据后数据也不会像管道那样就没了,写进程关闭了读进程也不会退出,也就是所谓数据不一致问题

        这样的话就需要用户自己去设定保护机制,这个保护机制要用信号量去控制,这个信号量我们后面会说,暂时我们先用命名管道保护。

        共享资源被保护起来,我们一般称之为临界资源

        访问公共资源的代码叫临界区,相反剩下的代码是非临界区。如果我们想把共享资源保护起来变成临界资源,就要对临界区进行加锁,这个话题我们也在后面会说。

        

补充:获取时间

        man localtime查看

        ​​​​​​​        

                

        localtime函数是一个系统调用

        参数是一个时间戳地址,返回值是tm结构体指针,我们也可以看到tm结构体中都包含了什么内容。

        获取时间戳就用time()函数就好了,之前随机值种子就是用这个函数返回的时间戳生成的。

        ​​​​​​​        

        获取到的年和月要注意有固定的+1900和+1才能拿到正确数据。

1.3.1 通讯

        我们给出的通讯保护方案就是client进程先向共享内存中写入信息,写完后向管道中发送一个信号;server进程一直等待管道中的信号,接收到信号之后再读共享内存中的内容。

        看起来不如直接使用管道,但其实因为向管道中传递的数据量较少,所以对整体通讯的速度影响也较小,我们可以使用共享内存来传输大块数据,用管道传输小块数据,来保证整体的通讯速度。

        我们让两个进程通讯以一定的顺序访问公共资源的方案叫进程间同步的过程。

        我们借用上节管道通讯中的部分代码进行信号标识工作。

完整代码

Time.hpp

#pragma once#include <iostream>
#include <string>
#include <time.h>std::string GetCurrTime()
{time_t t = time(nullptr);struct tm *curr = ::localtime(&t);char currtime[32];snprintf(currtime, sizeof(currtime), "%d-%d-%d %d:%d:%d",curr->tm_year + 1900, curr->tm_mon + 1, curr->tm_mday,curr->tm_hour, curr->tm_min, curr->tm_sec);return currtime;
}

Fifo.hpp

#pragma once#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>const std::string gpipeFile = "./fifo";
const mode_t gfifomode = 0600; // 允许拥有者读写
const int gdefualt = -1;   // 默认错误文件描述符
const int gsize = 1024;    // 约定通讯缓冲区大小const int gForRead = O_RDONLY;
const int gForWrite = O_WRONLY;class Fifo
{
private:void OpenFifo(int flag){_fd = ::open(gpipeFile.c_str(), flag);if (_fd < 0){std::cerr << "open error" << std::endl;}}public:Fifo() : _fd(-1){umask(0);int n = ::mkfifo(gpipeFile.c_str(), gfifomode);if (n < 0){std::cerr << "mkfifo error" << std::endl;return;}std::cout << "make fifo success!" << std::endl;}bool OpenPipeFWrite(){OpenFifo(gForWrite);if (_fd < 0){return false;}return true;}bool OpenPipeFRead(){OpenFifo(gForRead);if (_fd < 0){return false;}return true;}int Wait(){int code = 0;ssize_t n = ::read(_fd, &code, sizeof(code));if (n == sizeof(code))  //正常读到信号{return 0;}else if(n == 0) //对方退出了,管道文件关闭{return 1;}else    //其他错误{return 2;}}void Singal(){int code = 1;::write(_fd, &code, sizeof(code));}~Fifo(){if (_fd >= 0)::close(_fd);int n = unlink(gpipeFile.c_str());if (n < 0){std::cerr << "unlink error" << std::endl;return;}std::cout << "unlink fifo success!" << std::endl;}private:int _fd;
};Fifo gpipe;

ShareMemory.hpp

#pragma once#include <iostream>
#include <string>
#include <cstdio>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>const std::string gpath = "/home/atlanteep/Linux_learn";
int gprojId = 0x666;
int gshmsize = 4096;
mode_t gmode = 0600; // 拥有者读写权限全开std::string ToHex(key_t k)
{char buffer[64];snprintf(buffer, sizeof(buffer), "%x", k);return buffer;
}class ShareMemory
{
private:int CreatShmHelper(int shmflg){_k = ::ftok(gpath.c_str(), gprojId);if (_k < 0){std::cerr << "ftok error" << std::endl;return -1;}// 创建共享内存_shmid = ::shmget(_k, gshmsize, shmflg);if (_shmid < 0){std::cerr << "shm get error" << std::endl;return -2;}std::cout << "shmid:" << _shmid << std::endl;return _shmid;}public:ShareMemory() : _shmid(-1), _k(0), _addr(nullptr){}~ShareMemory() {}void CreatShm(){if (_shmid == -1)CreatShmHelper(IPC_CREAT | IPC_EXCL | gmode);}void GetShm(){CreatShmHelper(IPC_CREAT);}void AttachShm(){_addr = ::shmat(_shmid, nullptr, 0);if ((long long)_addr == -1){std::cout << "attach error!" << std::endl;}}void DetachShm(){if (_addr != nullptr)::shmdt(_addr);}void Delete(){shmctl(_shmid, IPC_RMID, nullptr);}void *GetAddr(){return _addr;}private:key_t _k; // 关键码int _shmid;void *_addr; // 起始地址
};ShareMemory shm;struct data
{char status[32];char lasttime[64];char image[1024];
};

server.cc

#include <iostream>
#include <string.h>
#include "ShareMemory.hpp"
#include "Time.hpp"
#include "Fifo.hpp"int main()
{// 创建共享内存shm.CreatShm();shm.AttachShm();// 打开管道gpipe.OpenPipeFRead();// 通讯struct data *image = (struct data *)shm.GetAddr();while (true){//阻塞等待另一个进程写完内容的信号gpipe.Wait();printf("status: %s\n", image->status);printf("lasttime: %s\n", image->lasttime);printf("image: %s\n", image->image);strcpy(image->status, "过期");}// sleep(10);shm.DetachShm();shm.Delete();return 0;
}

client.cc

#include <iostream>
#include <string.h>
#include "ShareMemory.hpp"
#include "Time.hpp"
#include "Fifo.hpp"int main()
{//先获取共享内存shm.GetShm();shm.AttachShm();//打开管道gpipe.OpenPipeFWrite();// 通讯struct data *image = (struct data *)shm.GetAddr();int num = 10;while(num--){strcpy(image->status, "最新");strcpy(image->lasttime, GetCurrTime().c_str());strcpy(image->image, "atlanteep picture");//写好消息了,用管道通知另一个进程gpipe.Singal();sleep(3);}    sleep(10);shm.DetachShm();return 0;
}

2. 消息队列

        system V 消息队列是内核提供的一种进程间通讯的方式。

        消息队列是存在于操作系统中的,其每个节点data的元素是由type标定发送进程,text存储具体数据。

        由进程A将要发送的信息传给消息队列由OS托管,在一定时机由OS再将消息给到进程B,反过来也是可以的,消息队列支持双向通讯,进程B将消息交给OS托管进而发送给进程A,其中type就能够标定消息是由谁发出的进而得知要发送给谁。

        消息队列的本质就是一个进程向另一个进程发送有类型数据块的方法。

        man msgget 查看

        ​​​​​​​        

        msgget()函数,创建消息队列

        第一个参数key,给OS看的唯一标识符,同样用ftok()生成

        第二个参数msgflg,常用两种选项IPC_CREAT    IPC_CREAT|IPC_EXCL,含义与共享内存的这两个选项一摸一样。

        返回值,也是一样的给用户看的唯一标识符

        

        man msgctl 查看

        ​​​​​​​        

        msgctl()函数,消息队列控制,常用删除消息队列

        第一个参数,给用户看的唯一标识符

        第二个参数,选择删除 IPC_RMID

        第三个参数是输出型参数,获取消息队列的各种属性

        ​​​​​​​        

        ipcrm -m (msqid) 指令层面删除消息队列 

        

        ipcs -q 单独查看消息队列

        ​​​​​​​        

        
       到这里我们发现消息队列的各种接口和选项都与共享内存有极大的相似性,这是因为它们都在system V标准下的产物,这就是标准的意义。

        当然它们不可能完全一样,还有一些个性化的接口,比如消息队列的发送和接收消息接口,与共享内存的挂接和去关联接口

        

        收发消息操作要求用户层自定义一个msgbuf结构体,mtype进程标志,mtext数据可以随意定制大小用于保存消息数据

                

        msgsnd()发送消息接口

        第一个参数msqid,给用户的唯一标识符

        第二个参数msgp,就是用户自定义的msgbuf

        第三个参数msgsz,用户自定义的消息大小,就是mtext[ ]数组大小

        第四个参数msgflg,不管设置成0

        msgrcv()接收消息接口

        跟msgsnd的接口几乎一样,就多了个msgtyp收哪个进程的消息

        

        消息队列资源必须手动删除,它不会随进程结束自动清除,其实所有system V IPC资源的声明周期都随内核

3. 信号量 semaphore

        semget() 获取信号量        semctl() 删除信号量

        因为同在system V标准下,信号量的接口也和共享内存与消息队列很像。

        ipcs -s单独查看信号量

        ​​​​​​​        ​​​​​​​        

        ipcrm -s (semid)命令删除某个信号量集

       

下面我们重述一下各概念

        多个执行流能看到同一份资源,则称这份资源为共享资源

        被保护起来的共享资源叫临界资源        

        保护的方式常用:同步互斥。任何时刻只允许一个执行流访问资源叫互斥,多个执行流访问临界资源的时候具有一定的顺序性叫做同步。

        涉及到访问临界资源的代码叫临界区,相反,不涉及临界资源的代码叫非临界区

        所谓对共享内存进行保护,本质上是对访问共享资源的代码进行保护。

        ​​​​​​​        ​​​​​​​        ​​​​​​​        

        

        信号量的本质是一个计数器

        之前我们对共享内存的操作都是整体使用,开出一大块空间之后,写进程在完全写完之后,读进程才能进来读。但是我们还可以将共享内存不是整体使用,比如一大块空间分成50个小区域,写进程写到第四块小区域的时候读进程从第一块小区域开始读,这样也能保证数据的完性。        

        通过我们上述的操作,完整了多个进程具有一定并发性的访问共享资源。

        但是这么做也有弊端,50个小区域,如果同时来了100个进程,那一定就会造成进程之间访问小区域的冲突,也就是如果资源不是整体使用,我们要避免过量的进程进入临界资源,操作可以简化成用一个计数器变量 num = 50,来标定剩余小区域,来一个进程使用区域就 num-- 出一个进程就num++,如果num == 0说明小区域都在被占用,那就拒绝再新来的进程进入共享资源。

        事实上进程没必要进入共享资源之后再对计数器进行操作,而是让进程可以预定一个区域,提前将计数器-- ,即使后面进程不来这个区域也要给进程留着。那这个以预定的计数器就叫信号量。

        信号量是可以对资源进行预定的计数器

        当我们把资源当作整体来用时,信号量要么为0要么为1,这种情况叫二元信号量,也是后面所谓的

        我们上面的例子是有问题的,首先多个进程之间无法看到同一份信号量,那如果我们把信号量弄到共享内存中去让各个进程去修改不就行了吗,确实,但此时又出现了一个问题,信号量变成了共享资源,那共享资源就需要保护,此时套娃开启了。

        计数器变成公共资源后,如果要保证自己的安全,就要让自增自减操作具有原子性,原本的自增自减操作虽然在C中是一条语句,但是在汇编中是多条,所以具有安全风险。

        将自减操作变成原子性后叫P操作,将自增操作具有原子性后叫V操作

3.1 信号量操作

        可能公共资源不止一大块,也就是说,信号量是以信号量集的方式申请的

        ​​​​​​​        ​​​​​​​        

        此时我们回过头看信号量申请函数,第二个参数nsems就是信号量集里要几个信号量。

        ​​​​​​​        ​​​​​​​        

        信号量控制函数中,第二个参数semnum就是信号量集的某一个信号量下标

        man semop查看

                

        第一个参数semid,给用户看的唯一标识符

        第二个参数sops是sembuf结构体的数组,也是一个需要自己定义的结构体,其成员如下

        ​​​​​​​        ​​​​​​​        

        结构体中sem_num表示信号量对应下标,sem_op -1为自减 1为自增,sem_flg 我们不管设置为0

        这个结构体让我们自定义提供信号量操作方案,信号量集中可能存在多个信号量,那我们也能提供对应的多个操作方案,合并成一个大数组

        第三个擦书nsops,就是数组的元素个数。

        由此sem支持了同时对多个信号量进行PV操作

4. IPC原理

        至此system V的三种IPC方案全部讲完,那它与之前的管道有什么不同呢?

        无论是共享内存,消息队列还是通讯,都有对应的模块属性,那共享内存的属性举例

        ​​​​​​​        

        ​​​​​​​        

        获取共享内存属性 IPC_STAT 选项

                ​​​​​​​

                        

        属性消息中,第一个是创建共享内存时的时间戳,第二个是当前进程pid,第三个访问时间,第四个挂接进程数,最后一个就是key值

        IPC资源一定是全局的资源,它需要被所有进程都看到,在操作系统层面,为我们维护了一个struct ipc_ids 这给结构体中有一个entries指针,entriens指向ipc_id_ary结构体,这个结构体中有一个柔性数组(变长数组),system V的IPC方案的每一个属性结构体的第一个成员都是struct ipc_perm结构体,刚才的柔性数组就指向这个结构体。

        这个变长数组的下标就是我们在***get(),比如shmget()创建共享内存时拿到的所谓给用户看的唯一标识符shmid,没错变长数组的下标就是***mid

        事实上当我们用柔性数组的元素指向ipc_perm结构体的时候,因为这个结构体是在各个方案的属性的首个成员,其地址就是某方案本身属性的起始,也就是说我们可以通过强转ipc_perm结构体地址的方式拿到整个方案的所有属性。

        这种通过一个指针指向结构体首成员地址从而可以访问部分成员和整体成员的现象,在C++中有一个更响亮的名字 多态 !!!ipc_perm结构就是基类,shmid_ds就是子类。

        最后一个问题,ipc_perm结构怎么知道自己目前所在哪个方案的属性结构体中,其实在操作系统中ipc_ids有3个,分别是sem_ids 、shm_ids 、msg_ids ,这三个结构体最终指向同一个荣幸数组表就好了。

相关文章:

Linux·进程控制(system V)

1. 共享内存 system V共享内存是最快的IPC形式&#xff0c;之前的管道是基于Linux内核开发的通讯方案&#xff0c;其读写接口都是现成的&#xff0c;因此内核设计者为了完成进程间通讯任务并不需要新增太多代码。而共享内存属于system V标准&#xff0c;是操作系统单独…...

华为云Stack名词解释

1、MRS MapReduce服务&#xff08;MRS&#xff09;是一种基于云计算平台的即开即用、稳定可靠、弹性伸缩、便捷管理的数据处理分析服务。 2、VBS 云硬盘备份服务&#xff08;VBS&#xff0c;Volume Backup Service&#xff09;可为云硬盘&#xff08;EVS&#xff0c;Elastic…...

YoloV9改进策略:上采样改进|CARAFE,轻量级上采样|即插即用|附改进方法+代码

论文介绍 CARAFE模块概述&#xff1a;本文介绍了一种名为CARAFE&#xff08;Content-Aware ReAssembly of FEatures&#xff09;的模块&#xff0c;它是一种用于特征上采样的新方法。应用场景&#xff1a;CARAFE模块旨在改进图像处理和计算机视觉任务中的上采样过程&#xff0…...

【C++】多态的语法与底层原理

1.多态的概念 1.1 概念 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会 产生出不同的状态。 举个例子&#xff1a;在现实当中&#xff0c;我们去火车站买票&#xff0c;一般都分三种情况&…...

RTP和RTCP的详细介绍及其C代码示例

RTP和RTCP的详细介绍及其C代码示例 RTP和RTCP简介RTP协议详解RTCP协议详解RTP和RTCP之间的关系C代码示例RTP和RTCP简介 RTP(Real-time Transport Protocol,实时传输协议)和RTCP(Real-time Transport Control Protocol,实时传输控制协议)是流媒体传输中常用的两个协议。R…...

深入浅出了解AI教育发展与落地应用情况

2023年,是生成式AI能力涌现的一年,通用大模型是其中的主旋律。经过一年的发展,通用大模型格局已初步形成,生成式AI也从能力展示走向应用落地。进入2024年,对生成式AI的讨论和实践也都转向如何赋能产业。相比于通用大模型,进入产业内的大模型需要的是对行业的Know-How,以…...

Hive数据库操作语法

数据类型 内部表和外部表 内部表 &#xff08;CREATE TABLE table_name ......&#xff09;未被external关键字修饰的即是内部表&#xff0c; 即普通表。 内部表又称管理表,内部表数据存储的位置由hive.metastore.warehouse.dir参数决定&#xff08;默认&#xff1a;/user/h…...

容器架构-Docker的成长之路

目录 1. 什么是容器 2. 容器 vs 虚拟机 3. Docker极速上手指南 环境准备 3.1 配置docker源 3.2 下载镜像加速的配置 3.3 下载自动补全工具 4. Docker C/S架构 5. Docker的镜像管理 5.1 下载nginx:alpine镜像并查看 5.2 sl大法 5.3 删除镜像 5.4 镜像清理用的命令 5…...

关于我、重生到500年前凭借C语言改变世界科技vlog.14——常见C语言算法

文章目录 1.冒泡排序2.二分查找3.转移表希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力&#xff01; 根据当前所学C语言知识&#xff0c;对前面知识进行及时的总结巩固&#xff0c;出了这么一篇 vlog 介绍当前所学知识能遇到的常见算法&#xff0c;这些算法是…...

简记Vue3(三)—— ref、props、生命周期、hooks

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…...

ARM cpu算力KDMIPS测试

一、引言 KDMIPS(KiloDhrystone Million Instructions Per Second)是一种衡量处理器性能的指标,它表示处理器每秒钟可以执行多少百万条Dhrystone指令。 二、测试说明 1、将cpu模式调整为perfermance 2、将cpu的频率和gpu的频率调大最大 3、将ddr和各core的电压和频率调大最…...

自杀一句话木马(访问后自动删除)

在做安全测试时&#xff0c;例如文件上传时就要上传可以解析的脚本文件解析证明存在漏洞&#xff0c;这个时候就需要(访问后自动删除文件的一句话木马) PHP <?php echo md5(1);unlink(__FILE__); ?> 访问后自动删除...

Nginx 反向代理(解决跨域)

文章目录 前言一、同源策略二、跨域是什么&#xff1f;三、Nginx解决跨域1.前端示例代码2.说明 四、nginx反向代理配置五、启动nginx六、最终效果总结 前言 Nginx反向代理解决跨域 一、同源策略 定义&#xff1a;同源策略&#xff08;Same-Origin Policy&#xff09;是指浏览…...

gRPC-4种通信模式

4种通信模式 1、简单模式&#xff08;Simple RPC&#xff09; 简单模式&#xff1a;也称简单 RPC&#xff0c;即客户端发起一次请求&#xff0c;服务端响应处理后返回一个结果给客户端。 在 proto 文件中可如下定义&#xff1a; rpc SayHello(HelloRequest) returns (Hello…...

第五项修炼—系统思考

感谢合作伙伴的推荐&#xff0c;圆满结束为期两天的马上消费《第五项修炼—系统思考》项目&#xff01;这不仅是一次培训&#xff0c;更是未来实践的起点。 两天的系统思考学习让我们看到&#xff0c;在技术管理的每个决策背后&#xff0c;都蕴含着深刻的系统关联。希望各位技…...

PYNQ 框架 - VDMA驱动 - 帧缓存

目录 1. 简介 2. 代码分析 2.1 _FrameCache 类定义 2.1.1 xlnk.cma_array() 2.1.2 pointerNone 2.1.3 PynqBuffer 2.2 _FrameCache 例化与调用 2.3 _FrameCache 测试 2.4 _FrameList 类定义 2.5 _FrameList 例化与调用 2.6 _FrameList 测试 3. 帧的使用 3.1 读取帧…...

Java导出Word文档的几种方法

文章目录 1. 使用 Apache POI2. 使用 Docx4j3. 使用 JODConverter4. 使用 FreeMarker 模板 在 Java 中导出 Word 文档可以通过多种库和方法实现。以下是几种常用的方法&#xff1a; 1. 使用 Apache POI Apache POI 是一个强大的库&#xff0c;可以用来读写 Microsoft Office 格…...

OceanBase V4.3.3,首个面向实时分析场景的GA版本发布

在10月23日举办的 OceanBase年度发布会 上&#xff0c;我们怀着激动之情&#xff0c;正式向大家宣布了 OceanBase 4.3.3 GA 版的正式发布&#xff0c;这也是OceanBase 为实时分析&#xff08;AP&#xff09;场景打造的首个GA版本。 2024 年初&#xff0c;我们推出了 4.3.0 版本…...

Maven随笔

文章目录 1、什么是MAVEN2、Maven模型3、Maven仓库4、项目集成1_Idea集成Maven设置2_创建Maven项目3_POM配置详解4_maven 坐标详情5_Maven工程类型6_导入Maven项目 5、依赖管理1_依赖配置2_依赖传递3_可选依赖4_排除依赖4_可选依赖和排除依赖的区别5_依赖范围6_继承与聚合7_版本…...

牛客题目解析

一.最长回文子串 1.题目&#xff1a;给定一个仅包含小写字母的字符串&#xff0c;求它的最长回文子串的长度。 最长回文子串__牛客网 2.算法原理&#xff1a; <1>动态规划算法:O(n^2),O(n^2) 具有通性&#xff0c;凡涉及回文子串的问题都可利用此法解决 知识储备&am…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...

对象回调初步研究

_OBJECT_TYPE结构分析 在介绍什么是对象回调前&#xff0c;首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例&#xff0c;用_OBJECT_TYPE这个结构来解析它&#xff0c;0x80处就是今天要介绍的回调链表&#xff0c;但是先不着急&#xff0c;先把目光…...

字符串哈希+KMP

P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...

shell脚本质数判断

shell脚本质数判断 shell输入一个正整数,判断是否为质数(素数&#xff09;shell求1-100内的质数shell求给定数组输出其中的质数 shell输入一个正整数,判断是否为质数(素数&#xff09; 思路&#xff1a; 1:1 2:1 2 3:1 2 3 4:1 2 3 4 5:1 2 3 4 5-------> 3:2 4:2 3 5:2 3…...