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

Linux进程间的通信

IPC 即 Inter-Process Communication,也就是进程间通信,它指的是在不同进程之间进行数据交换和协调同步的机制。在操作系统里,每个进程都有自己独立的内存空间,一般情况下不能直接访问其他进程的内存,所以需要借助 IPC 机制来实现进程间的信息交互与协作。

进程间通信常用的几种方式
1.管道通信:有名管道,无名管道
2.消息队列
3.共享内存
4.信号量
5.套接字

管道

管道的本质是内核中的一块缓冲区,它在内核空间中开辟了一段连续的内存区域,用于存储进程间传输的数据。在用户程序看来,管道表现为一对文件描述符,一个用于读操作,另一个用于写操作,进程可以像操作普通文件一样对管道进行读写操作,但实际上数据是在内存中的缓冲区里进行传输的。

匿名管道

数据传输:当一个进程向管道的写端写入数据时,数据会被复制到内核的管道缓冲区中;另一个进程从管道的读端读取数据时,数据会从管道缓冲区复制到该进程的用户空间。
亲缘关系要求:匿名管道只能用于具有亲缘关系的进程之间,如父子进程。这是因为创建管道后,只有创建管道的进程及其子进程才能访问这对文件描述符,其他进程无法获取这些文件描述符,也就无法访问该管道。

创建

匿名管道通过 pipe() 系统调用创建。pipe() 函数会在内核中创建一个管道,并返回两个文件描述符,一个是读端文件描述符(通常用 fd[0] 表示),另一个是写端文件描述符(通常用 fd[1] 表示)

#include <unistd.h>int pipe(int fd[2])/*fd‐传出参数:fd[0]‐读端fd[1]‐写端返回值:0:成功‐1:创建失败*/

管道的读写

 读操作
        有数据
          read(fd[1]) 正常读,返回读出的字节数
        无数据
          写端被全部关闭,read返回0,相当于读文件到了尾部
          没有全部关闭,read阻塞

 写操作
      读端全部关闭
          管道破裂,进程被终止
          内核给当前进程发送信号SIGPIPE-13,默认处理动作
      读端没全部关闭
          缓冲区写满了,write阻塞
          缓冲区没满,write继续写,直到写满,阻塞

如何设置非阻塞?


在管道的读写操作中,默认情况下是阻塞模式,即当管道没有数据可读或者管道已满无法写入时,相应的读或写操作会使进程阻塞等待。不过,你可以将管道设置为非阻塞模式,在这种模式下,当无法进行读写操作时,操作会立即返回而不会阻塞进程。

fcntl-变参函数


   复制文件描述符-dup
   修改文件属性-open的时候对应flag属性

设置方法

//获取原来的flags
int flags = fcntl(fd[0],F_GETFL);//设置新的flags
flags |=O_NONBLOCK;//将新的flags设置给文件描述符
fcntl(fd[0],F_SETFL,flags);

查看管道缓冲区的大小

命令
ulimit -a

函数
fpathconf

long size = fpathconf(fd[1],_PC_PIPE_BUF);printf("size is %ld\n",size);

举例:

父子进程使用管道通信
实现 ps aux| grep "bash"
 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main()
{int ret;int fd[2];ret = pipe(fd);if(ret == -1){printf("create pipe failed!\n");exit(1);}pid_t pid;pid = fork();if(pid == -1){printf("fork failed!\n");exit(1);}//ps auxif(pid>0){close(fd[0]);dup2(fd[1],STDOUT_FILENO);//数据重定向execlp("ps","ps","aux",NULL);perror("execlp");exit(1);}//grep "hash"else if(pid == 0){close(fd[1]);dup2(fd[0],STDIN_FILENO);execlp("grep","grep","bash","--color=auto",NULL);}//      long size = fpathconf(fd[1],_PC_PIPE_BUF);
//      printf("size is %ld\n",size);printf("pipe[0] is %d\n",fd[0]);printf("pipe[1] is %d\n",fd[1]);close(fd[0]);close(fd[1]);return 0;
}

有名管道

数据传输:与匿名管道类似,进程通过打开这个 FIFO 文件来获取管道的文件描述符,然后进行读写操作。数据同样是在内核的管道缓冲区中进行传输。
无亲缘关系限制:命名管道可以在任意两个进程之间使用,因为它有一个文件系统中的路径名,不同的进程可以通过该路径名打开同一个 FIFO 文件来访问管道。

创建

有名管道通过 mkfifo() 函数创建,它会在文件系统中创建一个特殊类型的文件(FIFO 文件)。这个文件并不实际存储数据,只是作为一个访问管道的接口。

#include <sys/types.h>
#include <sys/stat.h>int mkfifo(const char \*filename,mode_t mode);/*功能:创建管道文件参数:管道文件文件名,权限,创建的文件权限仍然和umask有关系。返回值:创建成功返回0,创建失败返回-1。*/

fifo文件可以使用io函数进程操作:open/close、read/write
不能执行lseek操作

有名管道的读写

读:

int main()
{int ret,fd,nread;char readBuff[50] = {0};ret = mkfifo("/home/cc/ipc/myfifo",0755);if(ret == -1 ){return -1;}printf("create fifo success!\n");fd = open("./myfifo",O_RDONLY);if(fd < 0){printf("open fifo  failed!\n");return -1;}printf("open fifo success!\n");nread = read(fd,readBuff,50);printf("read %d byte from fifo %s:\n ",nread,readBuff);close(fd);return 0;
}

写:

int main()
{int fd;char *str = "hello world!";fd = open("./myfifo",O_WRONLY);if(fd < 0){printf("open fifo  failed!\n");return -1;}printf("open fifo success!\n");write(fd,str,strlen(str));close(fd);return 0;
}

消息队列

特点:

消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级
消息队列独立于发送和接收进程,进程终止时,消息队列及其内容仍存在
消息队列可以实现消息的随机查询,消息不一定要先进先出的次序读取,也可以按消息的类型读取。

相关函数

1.创建或打开消息队列

在以下两种情况下,msgget将创建一个新的消息队列:
如果没有与键值key相对应的消息队列,并且flag中包含了IPC_CREAT标志
key参数为IPC_PRIVATE

 #include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgget(key_t key, int msgflg);/*参数:
key:和消息队列关联的key值
msgflg:是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。msgflg可以与IPC_CREAT做或
操作,表示当key所命名的消息队列不存在时创建一个消息队列,如果key所命名的消息队列存在时,IPC_CREAT标志会被忽略,而只返回一个标识符。
返回值:成功返回队列ID,失败则返回‐1*/

2.发送消息

 #include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);/*参数:
msgid:消息队列的ID
msgp:指向消息缓冲区的指针,消息缓冲区的第一个成员必须是 long 类型,表示消息的类型。常用结构体msgbuf如下:
struct msgbuf
{long mtype; //消息类型char mtext[N]; //消息正文
}
size:发送的消息正文的字节数
flag:IPC_NOWAIT 消息没有发送完成函数也会立即返回0:知道发送完成函数才返回
返回值:成功:0失败:‐1*/

3.接收消息

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);/*参数:
msgid:消息队列的ID
msgp:要接收消息的缓冲区
size:要接收的消息的字节数
msgtype:0:接收消息队列中第一个消息大于0:接收消息队列中第一个类型为msgtyp的消息小于0:接收消息队列中类型值不大于msgtyp的绝对值且类型值又最小的消息。
flag:0:若无消息函数一直阻塞IPC_NOWAIT:若没有消息,进程会立即返回ENOMSG。
返回值:成功:接收到的消息i长度出错:‐1*/

4.控制消息队列

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>int msgctl(int msqid, int cmd, struct msqid_ds *buf);/*参数:
msqid:消息队列的队列ID
cmd:IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆
盖msgid_ds的值。IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值IPC_RMID:删除消息队列
buf:是指向 msgid_ds 结构的指针,它指向消息队列模式和访问权限的结构
返回值:成功:0失败:‐1*/

5.ftok函数

系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值。通常情况下,该id值通过ftok函数得到。

#include <sys/types.h>
#include <sys/ipc.h>key_t ftok( char * fname, int id )/*参数:
fname就时你指定的文件名(该文件必须是存在而且可以访问的)。
id是子序号, 虽然为int,但是只有8个比特被使用(0‐255)。
返回值:
当成功执行的时候,一个key_t值将会被返回,否则 ‐1 被返回。*/

举例:

通过父子进程让两个进程间互相收发消息

进程1:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>struct msgbuf//magbuf结构体
{long mtype;char mtest[128];char ID[4];};int main()
{struct msgbuf sendbuf,readbuf;//定义读和写的结构体int msgid;key_t key;int readret;pid_t pid;key = ftok("a.c",1);//获取key值msgid = msgget(key,0755 | IPC_CREAT);//创建消息队列if(msgid == -1 ){printf("create message failed!\n");//创建失败就打印return -1;}printf("create message success! msgid is %d\n\n",msgid);//创建成功就打印system("ipcs -q");//查看队列信息//init msgbufsendbuf.mtype = 100;//发送消息的类型是100pid = fork();//创建子进程if(pid>0)//父进程发送类型为100的消息{while(1){memset(sendbuf.mtest,0,128);//初始化发送消息的数组printf("please input to message queue:\n");fgets(sendbuf.mtest,128,stdin);//向发送消息的数组输入消息//发送消息到消息队列msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.mtest),0);}}if(pid == 0)//子进程读取类型为200的消息{while(1){memset(readbuf.mtest,0,128);msgrcv(msgid,(void *)&readbuf,128,200,0);//读取消息到数组//打印读取到的消息printf("receive byte from message queue is: %s\n",readbuf.mtest);}}return 0;
}

进程2(读取类型为100的消息,发送类型为200的消息):

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>struct msgbuf
{long mtype;char mtest[128];char ID[4];
};int main()
{struct msgbuf sendbuf,readbuf;int msgid;key_t key;int readret;pid_t pid;key = ftok("a.c",1);msgid = msgget(key,0755 | IPC_CREAT);if(msgid == -1 ){printf("create message failed!\n");return -1;}printf("create message success! msgid is %d\n\n",msgid);system("ipcs -q");//init msgbufsendbuf.mtype = 200;pid = fork();if(pid == 0)//child process write 200{while(1){memset(sendbuf.mtest,0,128);printf("please input to message queue:\n");fgets(sendbuf.mtest,128,stdin);//send message to message queuemsgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.mtest),0);}}if(pid > 0)//parent process read 100{while(1){memset(readbuf.mtest,0,128);msgrcv(msgid,(void *)&readbuf,128,100,0);printf("receive byte from message queue is: %s\n",readbuf.mtest);}}return 0;
}

共享内存

概念:

共享内存(Shared Memory)就是允许多个进程访问同一个内存空间,是在多个进程之间共享和传递数据最高效的方式。操作系统将不同进程之间共享内存安排为同一段物理内存,进程可以将共享内存连接到它们自己的地址空间中,如果某个进程修改了共享内存中的数据,其它的进程读到的数据也将会改变。

特点:

1.共享内存创建之后,一直存在于内核中,直到被删除或系统关闭
2.共享内存和管道不一样,读取后,内容仍然在共享内存中
 

相关函数

1.获取或创建共享内存

#include <sys/ipc.h> 
#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);/*参数:
key:IPC_PRIVATE 或 ftok的返回值
size:共享内存区大小
shmflg:同open函数的权限位,也可以用8进制表示法
返回值:成功:共享内存段标识符‐‐‐ID‐‐‐文件描述符出错:‐1*/

2.把共享内存连接映射到当前进程的地址空间

#include <sys/types.h>
#include <sys/shm.h>void *shmat(int shm_id, const void *shm_addr, int shmflg);/*参数:
shm_id:ID号
shm_addr:映射到的地址,NULL为系统自动完成的映射
shmflg:SHM_RDONLY共享内存只读默认是0,表示共享内存可读写
返回值:成功:映射后的地址失败:NULL*/

3.将进程里的地址映射删除

#include <sys/types.h>
#include <sys/shm.h>int shmdt(const void *shmaddr);/*参数:
shmid:要操作的共享内存标识符
返回值:成功:0出错:‐1*/

4.删除共享内存对象

#include <sys/ipc.h>
#include <sys/shm.h>int shmctl(int shm_id, int command, struct shmid_ds *buf);/*参数:
shmid:要操作的共享内存标识符
cmd :IPC_STAT (获取对象属性)‐‐‐ 实现了命令ipcs ‐mIPC_SET (设置对象属性)IPC_RMID (删除对象) ‐‐‐实现了命令ipcrm ‐m
buf :指定IPC_STAT/IPC_SET时用以保存/设置属性
返回值:成功:0出错:‐1*/

举例:

不同进程用共享内存进行通信

写消息进程:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main()
{int shmid;key_t key;char *p;key = ftok("a.c",1);if(key < 0){printf("ftok failed!\n");return -1;}printf("ftok success! key is : %x\n",key);shmid = shmget(key,128,0777 | IPC_CREAT);if(shmid < 0){printf("create share memory failed!\n");return -1;}printf("create share memory success shmid = %d\n",shmid);system("ipcs -m");p = (char *) shmat(shmid,NULL,0);if(p == NULL){printf("shmat function failed!\n");return  -2;}//write to share memoryfgets(p,128,stdin);sleep(10);shmdt(p);shmctl(shmid,IPC_RMID,0);return 0;
}

收消息进程:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>int main()
{int shmid;key_t key;char *p;key = ftok("a.c",1);if(key < 0){printf("ftok failed!\n");return -1;}printf("ftok success! key is : %x\n",key);shmid = shmget(key,128,0);if(shmid < 0){printf("create share memory failed!\n");return -1;}printf("create share memory success shmid = %d\n",shmid);system("ipcs -m");p = (char *) shmat(shmid,NULL,0);if(p == NULL){printf("shmat function failed!\n");return  -2;}printf("share memory data:%s",p);shmdt(p);return 0;
}

信号

信号通信,其实就是内核向用户空间进程发送信号,只有内核才能发信号,用户空间进程不能发送信号。
使用命令"kill  -l"可以看到内核可以发送的信号

信号通信的框架
信号的发送(发送信号进程):kill、raise、alarm
信号的接收(接收信号进程) : pause()、 sleep、 while(1)
信号的处理(接收信号进程) :signal

1.信号的发送(发送信号进程)

kill

#include<signal.h>
#include<sys/types.h>
int kill(pid_t pid, int sig);/*参数:
函数传入值:pid
正数:要接收信号的进程的进程号
0:信号被发送到所有和pid进程在同一个进程组的进程
‐1:信号发给所有的进程表中的进程(除了进程号最大的进程外)
sig:信号
函数返回值:成功 0 出错 ‐1*/

2.发信号给自己

raise: 发信号给自己 == kill(getpid(), sig)

#include<signal.h>
#include<sys/types.h>int raise(int sig);/*参数:
函数传入值:sig:信号
函数返回值:
成功 0 出错 ‐1*/

3.发送闹钟信号

alarm 与 raise 函数的比较:
相同点:让内核发送信号给当前进程
不同点:
alarm 只会发送SIGALARM信号
alarm 会让内核定时一段时间之后发送信号, raise会让内核立刻发信号

#include <unistd.h>unsigned int alarm(unsigned int seconds)/*参数:
seconds:指定秒数
返回值:成功:如果调用此alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0。出错:‐1*/

4.信号的接收

pause 函数的作用是让调用进程暂停执行,直至收到一个能终止该进程或者使进程调用信号处理函数的信号

#include <unistd.h>int pause(void);//函数返回值 成功:0,出错:‐1

5.信号的处理

收到信号的进程,处理的方式:
1.进程的默认处理方式(内核为用户进程设置的默认处理方式)
A:忽略 B:终止进程 C: 暂停
2.自己的处理方式:
自己处理信号的方法告诉内核,这样你的进程收到了这个信号就会采用你自己的的处理方式

#include <signal.h>void (*signal(int signum, void (*handler)(int)))(int);/*参数
signum:指定信号
handlerSIG_IGN:忽略该信号。SIG_DFL:采用系统默认方式处理信号自定义的信号处理函数指针
函数返回值:成功:设置之前的信号处理方式出错:‐1
signal函数有二个参数,第一个参数是一个整形变量(信号值),
第二个参数是一个函数指针,是我们自己写的处理函数;
这个函数的返回值是一个函数指针*/

信号量

信号量集合(可以包含多个信号量)IPC对象是一个信号的集合(多个信号量)

1.创建或者获取一个信号量集

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>int semget(key_t key, int nsems, int semflg);/*函数参数:
key:和信号量集关联的key值
nsems: 信号量集中包含的信号量数目
semflg:信号量集的访问权限
函数返回值:成功:信号量集ID出错:‐1*/

2.控制信号量集

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>int semctl(int semid, int semnum, int cmd, ...);/*函数参数:
semid:信号量集ID
semnum: 要修改的信号量集中信号量编号
cmd :GETVAL:获取信号量的值SETVAL:设置信号量的值IPC_RMID:从系统中删除信号量集合
函数返回值:成功:0出错:‐1*//*在使用可变参数时,通常需要一个 union semun 类型的参数,该联合体的定义如下:
union semun {int  val;                //Value for SETVAL struct semid_ds *buf;    //Buffer for IPC_STAT, IPC_SETunsigned short  *array;  //Array for GETALL, SETALL struct seminfo  *__buf;  //Buffer for IPC_INFO(Linux-specific) 
};*/

参数说明:

semid
这是信号量集的标识符,由 semget 函数返回。它用于唯一标识要操作的信号量集。
semnum
表示信号量集中要操作的信号量的编号,编号从 0 开始。如果 cmd 命令不涉及特定的信号量(如 IPC_STAT、IPC_RMID 等),则该参数会被忽略。
cmd
这是一个整数,指定要执行的操作命令,常见的命令如下:
SETVAL:将信号量集中指定编号的信号量的值设置为 arg.val。
GETVAL:获取信号量集中指定编号的信号量的当前值。
SETALL:将信号量集中所有信号量的值设置为 arg.array 数组中的值。
GETALL:将信号量集中所有信号量的当前值存储到 arg.array 数组中。
IPC_STAT:获取信号量集的状态信息,并将其存储在 arg.buf 指向的 struct semid_ds 结构体中。
IPC_SET:将 arg.buf 指向的 struct semid_ds 结构体中的信息设置为信号量集的新状态。
IPC_RMID:删除指定的信号量集,此时 semnum 和 arg 参数会被忽略。
...(可变参数)
这是一个可变参数,根据 cmd 命令的不同,需要传递不同类型的 union semun 参数。如果 cmd 命令不需要额外的参数(如 IPC_RMID),则可以不传递该参数。


返回值:
若操作成功,不同的 cmd 命令会有不同的返回值:
对于 GETVAL 命令,返回指定信号量的当前值。
对于 GETALL 命令,返回 0。
对于 IPC_STAT、IPC_SET、SETVAL、SETALL、IPC_RMID 等命令,返回 0 表示操作成功。
若操作失败,返回 -1,并设置 errno 以指示错误类型。

PV操作

P 操作(申请资源)
功能:P 操作用于申请资源,当一个进程执行 P 操作时,它会尝试获取一个资源。
执行过程:
首先将信号量的值减 1。
检查信号量的值:
如果信号量的值大于等于 0,说明有可用资源,进程可以继续执行。
如果信号量的值小于 0,说明没有可用资源,进程会被阻塞,进入等待队列,直到有其他进程释放资源。
V 操作(释放资源)
功能:V 操作用于释放资源,当一个进程执行 V 操作时,它会释放一个资源。
执行过程:
首先将信号量的值加 1。
检查信号量的值:
如果信号量的值小于等于 0,说明有进程在等待该资源,会唤醒等待队列中的一个进程。
如果信号量的值大于 0,说明没有进程在等待该资源,进程继续执行。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>int semop(int semid, struct sembuf *sops, size_t nsops);/*参数:
semid : 信号量的标识码。也就是semget()的返回值
sops是一个指向结构体数组的指针。
struct sembuf
{unsigned short sem_num;//信号量编号;short sem_op;   //对该信号量的操作。‐1 ,P操作,1 ,V操作short sem_flg;  //0阻塞,1非阻塞
};
nsops: 操作信号量的个数
返回值:如果操作成功,semop 函数返回 0。如果操作失败,返回 -1 */

相关文章:

Linux进程间的通信

IPC 即 Inter-Process Communication&#xff0c;也就是进程间通信&#xff0c;它指的是在不同进程之间进行数据交换和协调同步的机制。在操作系统里&#xff0c;每个进程都有自己独立的内存空间&#xff0c;一般情况下不能直接访问其他进程的内存&#xff0c;所以需要借助 IPC…...

常用非对称加密算法的Python实现及详解

非对称加密算法&#xff08;Asymmetric Encryption&#xff09;使用公钥加密、私钥解密&#xff0c;解决了对称加密的密钥分发问题。本文将详细介绍 RSA、ECC、ElGamal、DSA、ECDSA、Ed25519 等非对称加密算法的原理&#xff0c;并提供Python实现代码及安全性分析。 1. 非对称加…...

【题解-洛谷】B4303 [蓝桥杯青少年组省赛 2024] 字母移位

题目&#xff1a;B4303 [蓝桥杯青少年组省赛 2024] 字母移位 题目描述 字母移位表示将字母按照字母表的顺序进行移动。 例如&#xff0c; b \texttt{b} b 向右移动一位是 c \texttt{c} c&#xff0c; f \texttt{f} f 向左移动两位是 d \texttt{d} d。 特别地&#xff0c;…...

详讲viewer查看器

将Python与Cesium结合起来&#xff0c;可以实现高效的数据处理与可视化展示。本文将详细介绍如何在Python环境中集成Cesium&#xff0c;以及实现数据可视化的具体方法。 我们可以通过在app.vue中的修改来更改我们查看器的显示方法 修改前 修改后 还可以进行各式各样的自定义操作…...

开关电源原理

开关电源原理 一、 开关电源的电路组成&#xff1a; 开关电源的主要电路是由输入电磁干扰滤波器&#xff08;EMI&#xff09;、整流滤波电路、功率变换电路、PWM控制器电路、输出整流滤波电路组成。辅助电路有输入过欠压保护电路、输出过欠压保护电路、输出过流保护电路、输出短…...

数据库的并发控制

并发控制 12.1 并发级别 问题&#xff1a;交错的读写 并发客户端可以随意进入和退出事务&#xff0c;并在中途请求读取和写入。为了简化分析&#xff0c;假设enter/exit/read/write是原子步骤&#xff0c;因此并发事务只是这些步骤的交错。 我们还将区分只读事务和读写事务…...

力扣第448场周赛

赛时成绩如下: 这应该是我力扣周赛的最好成绩了(虽然还是三题) 1. 两个数字的最大乘积 给定一个正整数 n。 返回 任意两位数字 相乘所得的 最大 乘积。 注意&#xff1a;如果某个数字在 n 中出现多次&#xff0c;你可以多次使用该数字。 示例 1&#xff1a; 输入&#xff1…...

关于Python:9. 深入理解Python运行机制

一、Python内存管理&#xff08;引用计数、垃圾回收&#xff09; Python&#xff08;CPython&#xff09;采用的是&#xff1a; “引用计数为主&#xff0c;垃圾回收为辅” 的内存管理机制。 也就是说&#xff1a; 引用计数机制&#xff1a;负责大部分内存释放&#xff0c;简…...

Cron表达式的用法

最近几天开发东西用到了定时脚本的问题&#xff0c;中间隔了一段时间没有用到&#xff0c;再次复习一下Cron表达式的用法。 Cron表达式是一种用于定义定时任务执行时间的字符串格式&#xff0c;广泛应用于Unix/Linux系统以及各种编程语言中。其主要用途是通过灵活的时间规则来…...

手机通过局域网访问网狐接口及管理后台网站

1.本地部署接口及后台网站 2.设置允许网站端口通过防火墙 3.查看网站服务器IP 4.手机连接到本地服务器同一局域网 5.手机访问本地服务器接口...

JavaSE核心知识点01基础语法01-01(关键字、标识符、变量)

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 JavaSE核心知识点01基础语法01-01&#xff0…...

Sliding Window Attention(Longformer)

最简单的自注意力大家肯定都会啦。 但这种全连接的自注意力&#xff08;即每个 token 需要 attend 到输入序列中的所有其他 token&#xff09;计算与内存开销是 O ( n 2 ) O(n^2) O(n2) 。为了缓解这个问题&#xff0c;研究者们提出了 Sliding Window Attention。 Sliding W…...

ROS2 开发踩坑记录(持续更新...)

1. 从find_package(xxx REQUIRED)说起&#xff0c;如何引用其他package(包&#xff09; 查看包的安装位置和include路径详细文件列表 例如&#xff0c;xxx包名为pluginlib # 查看 pluginlib 的安装位置 dpkg -L ros-${ROS_DISTRO}-pluginlib | grep include 这条指令的目的是…...

刷leetcodehot100返航版--哈希表5/5、5/6

回顾一下之前做的哈希&#xff0c;貌似只有用到 unordered_set&#xff1a;存储无序元素unordered_map&#xff1a;存储无序键值对 代码随想录 常用代码模板2——数据结构 - AcWing C知识回顾-CSDN博客 1.两数之和5/5【30min】 1. 两数之和 - 力扣&#xff08;LeetCode&am…...

嵌入式开发学习日志Day13

第九章 预处理命令 前面加“#”的都为预处理命令&#xff1b; 预处理命令是无脑的文本替换&#xff1b; 一、宏定义 1、不带参数的宏定义 一般形式为&#xff1a; #define 标识符 字符串 &#xff08;谷歌规定&#xff09;&#xff1a;所有的宏名均大写&#xff0c;便于…...

AI预测的艺术品走势靠谱吗?

首席数据官高鹏律师团队 AI预测艺术品价格走势&#xff1a;技术与法律的双重考量在当今数字化浪潮席卷全球的时代&#xff0c;人工智能&#xff08;AI&#xff09;技术正以前所未有的速度渗透到各个领域&#xff0c;艺术品市场也不例外。AI预测艺术品价格走势这一新兴事物&…...

AVL树 和 红黑树 的插入算法

1.AVL树 按照二叉搜索树的规则找到要插入的位置并插入&#xff0c;插入过后看是父节点的左还是右孩子&#xff0c;然后把父节点的平衡因子-1或1&#xff0c;调整后如果父节点的平衡因子是0&#xff0c;那就说明这颗子树的高度插入前后不变&#xff0c;上面的就不用调整平衡因子…...

【项目】基于ArkTS的网吧会员应用开发(1)

一、效果图展示 二、界面讲解 以上是基于ArkTS的鸿蒙应用网吧会员软件的引导页&#xff0c;使用滑动组件滑动页面&#xff0c;至最后一页时&#xff0c;点击立即体验&#xff0c;进入登录页面。 三、代码演示 import promptAction from ohos.promptAction; import router fr…...

命令模式(Command Pattern)

非常好&#xff01;现在我们来深入讲解行为型设计模式之一 —— 命令模式&#xff08;Command Pattern&#xff09;。 我将通过&#xff1a; ✅ 定义解释 &#x1f3af; 使用动机 &#x1f40d; Python 完整调用代码&#xff08;含注释&#xff09; &#x1f9ed; 清晰类图 …...

CMake基础介绍

1、CMake 概述 CMake 是一个项目构建工具&#xff0c;并且是跨平台的&#xff1b;关于项目构建目前比较流行的还有 Makefile(通过 Make 命令进行项目的构建)&#xff0c; 大多 IDE 软件都集成了 make,比如&#xff1a;VS 的 nmake、linux 下的 GNU make、Qt 的 qmake 等&…...

偷钱包行为检测数据集VOC+YOLO格式922张1类别有增强

有320张图片是原图剩余为增强图片 数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;922 标注数量(xml文件个数)&#xff1a;922 标注数量…...

C 语言比较运算符:程序如何做出“判断”?

各类资料学习下载合集 ​​https://pan.quark.cn/s/8c91ccb5a474​​ 在编写程序时,我们经常需要根据不同的条件来执行不同的代码。比如,如果一个分数大于 60 分,就判断为及格;如果用户的年龄小于 18 岁,就禁止访问某个内容等等。这些“判断”的核心,就依赖于程序能够比…...

Webug4.0靶场通关笔记16- 第20关文件上传(截断上传)

目录 第20关 文件上传(截断上传) 1.打开靶场 2.源码分析 &#xff08;1&#xff09;右键查看前端源码 &#xff08;2&#xff09;服务端源码分析 &#xff08;3&#xff09;渗透思路 3.渗透实战 &#xff08;1&#xff09;构建脚本 &#xff08;2&#xff09;bp抓包 …...

10 种最新的思维链(Chain-of-Thought, CoT)增强方法

防御式链式思维&#xff08;Chain-of-Defensive-Thought&#xff09; 该方法通过引入结构化、防御性的推理示例&#xff0c;提高大语言模型在面对被污染或误导信息时的稳健性。 &#x1f4c4; 论文链接&#xff1a;https://arxiv.org/abs/2504.20769 混合链式思维&#xff08;…...

力扣119题解

记录 2025.5.5 题目&#xff1a; 思路&#xff1a; 代码: class Solution {public List<Integer> getRow(int rowIndex) {List<Integer> row new ArrayList<Integer>();row.add(1);for (int i 1; i < rowIndex; i) {row.add((int) ((long) row.get(i…...

NSOperation深入解析:从使用到底层原理

1. 基础概念与使用 1.1 NSOperation概述 NSOperation是Apple提供的一个面向对象的并发编程API&#xff0c;它基于GCD&#xff08;Grand Central Dispatch&#xff09;构建&#xff0c;但提供了更高层次的抽象和更丰富的功能。NSOperation允许开发者以面向对象的方式管理并发任…...

suna工具调用可视化界面实现原理分析(二)

这是一个基于React的浏览器操作可视化调试组件&#xff0c;主要用于在AI开发工具中展示网页自动化操作过程&#xff08;如导航、点击、表单填写等&#xff09;的执行状态和结果。以下是关键技术组件和功能亮点的解析&#xff1a; 一、核心功能模块 浏览器操作状态可视化 • 实时…...

【大模型面试每日一题】Day 9:BERT 的 MLM 和 GPT 的 Next Token Prediction 有什么区别?

【大模型面试每日一题】Day 9&#xff1a;BERT 的 MLM 和 GPT 的 Next Token Prediction 有什么区别&#xff1f; &#x1f4cc; 题目重现 &#x1f31f; 面试官&#xff1a;预训练任务中&#xff0c;BERT 的 MLM&#xff08;Masked Language Modeling&#xff09;和 GPT 的 …...

分析strtol(),strtoul()和strtod()三个函数的功能

字符串转换为数值部分和子字符串首地址的函数有strtol(),strtoul()和strtod()三个函数。 1、strtol()函数 long int strtol(const char *str, char **endptr, int base) //当base0时,若字符串不是以"0","0x"和"0X"开头,则将数字部分按照10进制…...

Spring Boot 加载application.properties或application.yml配置文件的位置顺序。

我换一种更通俗易懂的方式&#xff0c;结合具体例子来解释 Spring Boot 加载application.properties或application.yml配置文件的位置顺序。 生活场景类比 想象你要找一本书&#xff0c;你有几个可能存放这本书的地方&#xff0c;你会按照一定顺序去这些地方找&#xff0c;直…...

C++进阶之——多态

1. 多态的概念 多态是用来描述这个世界的 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会 产生出不同的状态。 这里就很厉害了&#xff0c;能够实现特殊处理&#xff0c;本文章就是来仔细…...

第13项三期,入组1123例:默沙东启动TROP2 ADC+PD-1子宫内膜癌头对头临床

Umabs DB作为目前全球最全面的抗体药物专业数据库&#xff0c;收录全球近10000个从临床前到商业化阶段抗体药物&#xff0c;涉及靶点1600&#xff0c;涉及疾病种类2400&#xff0c;研发机构2900&#xff0c;覆盖药物蛋白序列、专利和临床等多种专业信息。Umabs DB药物数据库已正…...

政务服务智能化改造方案和案例分析

政务服务智能化改造方案和案例分析 一、引言 在数字化时代浪潮的推动下&#xff0c;政务服务智能化改造已成为提升政府服务效能、优化营商环境、增强民众满意度的关键举措。传统政务服务模式存在流程繁琐、信息孤岛、办理效率低等问题&#xff0c;难以满足现代社会快节奏发展和…...

15.日志分析入门

日志分析入门 第一部分&#xff1a;日志分析基础第二部分&#xff1a;日志分析方法与工具第三部分&#xff1a;日志分析实践总结 目标&#xff1a; • 理解日志分析在网络安全中的作用 • 掌握日志的基本类型和分析方法 • 通过实践初步体验日志分析的过程 第一部分&#xff…...

EPSG:3857 和 EPSG:4326 的区别

EPSG:3857 和 EPSG:4326 是两种常用的空间参考系统&#xff0c;主要区别在于坐标表示方式和应用场景。以下是它们的核心差异&#xff1a; 1. 坐标系类型 EPSG:4326&#xff08;WGS84&#xff09; 地理坐标系&#xff08;Geographic Coordinate System&#xff09;&#xff0c;基…...

Python Cookbook-7.2 使用 pickle 和 cPickle 模块序列化数据

任务 你想以某种可以接受的速度序列化和重建Python 数据结构&#xff0c;这些数据既包括基本Python 对象也包括类和实例。 解决方案 如果你不想假设你的数据完全由基本 Python 对象组成&#xff0c;或者需要在不同的 Python 版本之间移植&#xff0c;再或者需要将序列化后的…...

Java学习手册:Spring 多数据源配置与管理

在实际开发中&#xff0c;有时需要连接多个数据库&#xff0c;例如&#xff0c;一个系统可能需要从不同的数据库中读取和写入数据。Spring 提供了多种方式来配置和管理多数据源&#xff0c;以下将介绍常见的配置和管理方法。 一、多数据源配置 在 Spring 中&#xff0c;可以通…...

六、shell脚本--正则表达式:玩转文本匹配的“万能钥匙”

想象一下&#xff0c;你需要在一大堆文本&#xff08;比如日志文件、配置文件、网页代码&#xff09;里查找符合某种特定模式的字符串&#xff0c;而不是仅仅查找固定的单词。比如说&#xff1a; 找出所有的电子邮件地址 &#x1f4e7;。找到所有看起来像电话号码 &#x1f4d…...

Gradio全解20——Streaming:流式传输的多媒体应用(4)——基于Groq的带自动语音检测功能的多模态Gradio应用

Gradio全解20——Streaming&#xff1a;流式传输的多媒体应用&#xff08;4&#xff09;——基于Groq的带自动语音检测功能的多模态Gradio应用 本篇摘要20. Streaming&#xff1a;流式传输的多媒体应用20.4 基于Groq的带自动语音检测功能的多模态Gradio应用20.4.1 组件及配置1.…...

力扣hot100 (除自身以外数组的乘积)

238. 除自身以外数组的乘积 中等 给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除…...

LFU算法解析

文章目录 LFU缓存中关键变量的访问与更新机制1. min_freq - 最小频率访问时机更新时机更新示例 2. capacity - 缓存容量访问时机更新时机访问示例 3. key_to_node - 键到节点的映射访问时机更新时机更新示例 4. freq_to_dummy - 频率到链表哑节点的映射访问时机更新时机更新示例…...

RHCSA笔记2

RHCSA基础命令 &#xff08;一&#xff09;命令格式 &#xff08;1&#xff09;命令名【选项】【参数】 选项&#xff1a;决定命令执行的方式&#xff0c;通常有个-或--开头 参数&#xff1a;决定命令作用的目标&#xff08;目录&#xff0c;文件&#xff0c;磁盘&#xff…...

JavaSE核心知识点01基础语法01-02(基本数据类型、运算符、运算符优先级)

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 JavaSE核心知识点01基础语法01-02&#xff0…...

FOC算法开环控制基础

1. 为什么要有FOC算法 先看看从有刷电机到无刷电机的简单介绍&#xff0c;如下图1&#xff0c;通电螺线圈会产生磁场&#xff0c;这个磁场会产生N级和S级&#xff0c;然后这个电磁铁就可以吸引永磁体&#xff0c;S级吸引N级&#xff0c;N级吸引S级&#xff0c;通俗的来说&…...

进程间通信——管道

概念 进程间通信&#xff08;Inter-Process Communication&#xff0c;简称 IPC&#xff09;是指在不同进程之间进行数据交换和信息传递的机制。它的目的主要有4种&#xff1a; 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程资源共享&#xff1a;多个进程之间…...

五一作业-day02

文章目录 1. 每日基操2. 模拟故障2.1 **remove regular empty file 是否删除普通文件(空的)?**2.2 **is a directory xxx是一个目录**2.3 **xxx not a directory 不是一个目录**2.4 Cant open file for writing2.5 **No write since last change** 3. 习题4. **进阶习题** 1. …...

Springclound常用五大组件及其使用原理

注册中心Eureka Eureka-Server&#xff1a;就是服务注册中心&#xff08;可以是一个集群&#xff09;&#xff0c;对外暴露自己的地址。 提供者&#xff1a;启动后向Eureka注册自己信息&#xff08;地址&#xff0c;服务名称等&#xff09;&#xff0c;并且定期进行服务续约 …...

Qt 显示QRegExp 和 QtXml 不存在问题

QRegExp 和 QtXml 问题 在Qt6 中 已被弃用&#xff1b; 1&#xff09;QRegExp 已被弃用&#xff0c;改用 QRegularExpression Qt5 → Qt6 重大变更&#xff1a;QRegExp 被移到了 Qt5Compat 模块&#xff0c;默认不在 Qt6 核心模块中。 错误类型解决方法QRegExp 找不到改用 Q…...

开元类双端互动组件部署实战全流程教程(第4部分:后台配置系统与参数动态控制)

作者&#xff1a;曾经因为后台配置写错&#xff0c;导致全服进不去房的工程师 组件附带的后台管理系统为 PHP 编写&#xff0c;界面简洁但功能齐全。具备完整的模块划分与权限体系&#xff0c;支持动态参数下发、日志审计、行为数据统计等。 七、前端后台交互流程图与代码示例 …...

MySQL基础关键_008_DDL 和 DML(一)

目 录 一、DDL 1.创建表 &#xff08;1&#xff09;语法格式 &#xff08;2&#xff09;实例 2.查看建表语句 &#xff08;1&#xff09;语法格式 &#xff08;2&#xff09;实例 3.修改表名 &#xff08;1&#xff09;语法格式 &#xff08;2&#xff09;实例 4.新…...