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

【Linux C | 进程】Linux 进程间通信的10种方式(1)

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍 🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭

本文未经允许,不得转发!!!

目录

  • 🎄一、管道(无名管道)
    • ✨1.1 管道介绍
    • ✨1.2 例子
  • 🎄二、命名管道FIFO
    • ✨2.1 命名管道FIFO介绍
    • ✨2.2 例子
  • 🎄三、消息队列(System V IPC)
    • ✨3.1 消息队列(System V IPC)介绍
    • ✨3.2 例子
  • 🎄四、信号量(System V IPC)
    • ✨4.1 消息队列(System V IPC)介绍
    • ✨4.2 例子
  • 🎄五、共享内存(System V IPC)
    • ✨5.1 共享内存(System V IPC)介绍
    • ✨5.2 例子
  • 🎄六、总结


在这里插入图片描述
下表是进程间通信的十种方式

🎄一、管道(无名管道)

✨1.1 管道介绍

管道是半双工的通信方式,数据只能单向流动,管道的作用是在有亲缘关系的进程之间传递消息。所谓亲缘关系是指,只要调用进程使用pipe函数, 打开的管道文件就会在fork之后, 被各个后代进程所共享。

这个无名管道可以理解为:没有实体文件与之关联, 靠的是世代相传的文件描述符来进行数据的读写。

无名管道可以使用函数pipe来创建,函数原型如下:

#include <unistd.h>
int pipe(int pipefd[2]);

✨1.2 例子

看使用例子,父进程调用了pipe函数创建了管道文件,fork之后的子进程可以直接使用管道文件:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>  #define PIPE_INPUT		0
#define PIPE_OUTPUT		1int main()
{int pipe_fds[2];pipe(pipe_fds); // 创建无名管道pid_t pid = fork();if(pid == 0) {// 子进程printf("子进程[%d]开始执行, 关闭输入管道,写数据到输出管道\n", getpid()); close(pipe_fds[PIPE_INPUT]);// 关闭输入管道write(pipe_fds[PIPE_OUTPUT], "test data", strlen("test data"));// 写入管道exit(0);}else if(pid > 0){sleep(2); //延时一会,让子进程先运行printf("父进程[%d]开始执行, 关闭输出管道,读取管道数据\n", getpid()); close(pipe_fds[PIPE_OUTPUT]);// 关闭输出管道char buf[256] = {0,};int readSize = read(pipe_fds[PIPE_INPUT], buf, sizeof(buf));printf("父进程[%d]从管道读取到%d个字节的数据[%s]\n", getpid(), readSize, buf); exit(0);}else{printf("Error in fork\n"); exit(1); }return 0;
}

在这里插入图片描述

🎄二、命名管道FIFO

✨2.1 命名管道FIFO介绍

上面的无名管道没有与实体文件关联,靠的是世代相传的文件描述符来进行数据交换。命名管道就是为了解决无名管道的这个问题而引入的。 FIFO与管道类似, 最大的差别就是有实体文件与之关联。 由于存在实体文件, 不相关的、没有亲缘关系的进程也可以通过使用FIFO来实现进程之间的通信。

创建命名管道的3种方式:

  • 1、调用C语言接口函数mkfifo创建:mkfifo("my_fifo", 0666);
    #include <sys/types.h>
    #include <sys/stat.h>
    int mkfifo(const char *pathname, mode_t mode);
    
  • 2、使用mkfifo命令创建:mkfifo -m 0666 my_fifo
  • 3、使用mknod命令创建:mknod -m 0666 my_fifo p

一旦FIFO文件创建好了, 就可以把它用于进程间的通信了。 一般的文件操作函数如open、 read、 write、 close、 unlink等都可以用在FIFO文件上。

✨2.2 例子

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{if(0 == access("./my_fifo",F_OK)){system("rm ./my_fifo");}/*创建管道文件, 下次运行需要先删除my_fifo文件,否则mkfifo报错*/if(mkfifo("my_fifo", 0666) < 0){perror("mkfifo");return -1;}pid_t pid = fork();if(pid == 0) {// 子进程printf("子进程[%d]开始执行, 打开my_fifo文件,循环往里写数据\n", getpid());int fd = open("my_fifo", O_WRONLY);if(fd < 0){return -1;}int i = 9;while(i>=0){printf("子进程[%d]写入数据:%d\n", getpid(), i);char buf[256] = {0,};sprintf(buf,"%d",i);write(fd, buf, strlen(buf));i--;sleep(1);}close(fd);printf("子进程[%d]退出\n", getpid());return 0;}else if(pid > 0)// 父进程{sleep(5); //延时一会,让子进程先运行printf("父进程[%d]开始执行, 打开my_fifo文件,读取数据\n", getpid()); int fd = open("my_fifo", O_RDONLY);if(fd < 0){return -1;}char buf[256] = {0,};int readSize = 0;while((readSize = read(fd, buf, sizeof(buf)) ) > 0){printf("父进程[%d]读取到%d个字节数据:[%s]\n", getpid(),readSize, buf);memset(buf, 0, sizeof(buf));}close(fd);printf("父进程[%d]退出\n", getpid());return 0;}else{printf("Error in fork\n"); exit(1); }return 0;
}

运行结果:
在这里插入图片描述

在这里插入图片描述

🎄三、消息队列(System V IPC)

✨3.1 消息队列(System V IPC)介绍

有三种被称为XSI IPC的进程间通信,消息队列,信号量,共享内存。XSI IPC函数是基于System V的IPC函数。这里介绍的消息队列就属于其中一种,后面还有介绍其余两种,消息队列比较少用了,是一种逐渐被淘汰的通信方式,为了完整性,这里还是介绍一下,感兴趣的可以继续了解。

前面的管道通信,如果从管道中读取到100个字节,你无法确认这100个字节是单次写入的100字节, 还是分10次每次10字节写入的, 你也无法知晓这100个字节是几个消息。System V消息队列就不存在这种问题,因为它是基于消息通信的。无需从字节流解析完整的消息,而且每个消息有type字段作为消息类型。

消息队列编程步骤:

  • 1、生成 key,System V IPC的标识ID都是通过key来获取的,key的生成方式有三种:
    ①随机选择一个整数值作为key值,这个值必须不和其他key重复,例如:#define MSG_KEY 10086
    ②使用IPC_PRIVATE,例如:id = msgget(IPC_PRIVATE,S_IRUSR | S_IWUSR);
    ③使用ftok函数, 根据文件名生成一个key,例如:key_t key = ftok(".", 100);
  • 2、使用msgget()创建/获取消息队列,返回值为队列标识符。
    服务端创建:int msgid = msgget(key, 0666|IPC_CREAT);
    客户端获取:int msgid = msgget(key, 0);
  • 3、写入/取出消息;
    服务端写入:msgsnd(msgid, &msg, sizeof(msg.buf), 0);
    客户端获取:msgrcv(msgid, &msg, sizeof(msg)-sizeof(long), 0, 0);
  • 4、msgctl删除消息队列
    msgctl(msgid, IPC_RMID, NULL);

✨3.2 例子

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>typedef struct _MSG_TYPE
{long mtype;//消息类型char buf[256];//有效数据
}MSG_TYPE;int main()
{// 1 生成keykey_t key = ftok(".", 100);// 2 创建子进程pid_t pid = fork();if(pid == 0) {// 子进程printf("子进程[%d]开始执行, 创建消息队列,循环往里写数据\n", getpid());// 创建消息队列int msgid = msgget(key, 0666|IPC_CREAT);if(msgid == -1){perror("msgget failed");exit(1);}// 发送数据int i = 9;MSG_TYPE msg;while(i>=0){memset(&msg, 0, sizeof(msg));msg.mtype = i;sprintf(msg.buf, "hello-%d", i);msgsnd(msgid, &msg, sizeof(msg.buf), 0);//阻塞printf("子进程[%d]写入数据:hello-%d\n", getpid(), i);i--;sleep(1);}// 删除队列if(msgctl(msgid, IPC_RMID, NULL) == -1){perror("msgctl failed");exit(3);}printf("子进程[%d]退出\n", getpid());return 0;}else if(pid > 0)// 父进程{sleep(3); //延时一会,让子进程先运行printf("父进程[%d]开始执行, 获取消息队列,读取数据\n", getpid()); int msgid = msgget(key, 0); if(msgid == -1){perror("msgget failed");exit(1);}MSG_TYPE msg;while(1){memset(&msg, 0, sizeof(msg));int res = msgrcv(msgid, &msg, sizeof(msg)-sizeof(long), 0, 0);//阻塞printf("res=%d, 消息:%s, 类型:%ld\n", res, msg.buf, msg.mtype);if(res == -1){perror("msgrcv failed");break;}}// 删除队列if(msgctl(msgid, IPC_RMID, NULL) == -1){perror("msgctl failed");exit(3);}printf("父进程[%d]退出\n", getpid());return 0;}else{printf("Error in fork\n"); exit(1); }return 0;
}

运行结果:
在这里插入图片描述

在这里插入图片描述

🎄四、信号量(System V IPC)

✨4.1 消息队列(System V IPC)介绍

信号量的作用是为了同步多个进程的操作。一般来说, 信号量是和某种预先定义的资源相关联的。

信号量是一个计数器,控制访问共享资源的最大并行进程总数。可以通过下面这个故事来了解信号量。

一套豪宅里有8个一模一样的卫生间和8把通用的钥匙。最初有8把钥匙放在钥匙存放处。 当同时使用卫生间的人数小于或等于8时, 大家都可以拿到一把钥匙, 各自使用各自的卫生间。 但是到第9个人和第10个人要使用卫生间时, 发现已经没有钥匙了, 所以他们就不得不等待了。

使用最广泛的信号量是二值信号量(binary semaphore), 对于这种信号量而言, 它只有两种合法值: 0和1, 对应一个可用的资源。 若当前有资源可用, 则与之对应的二值信号量的值为1; 若资源已被占用, 则与之对应的二值信号量的值为0。 当进程申请资源时, 如果当前信号量的值为0, 那么进程会陷入阻塞, 直到有其他进程释放资源, 将信号量的值加1才能被唤醒。

资源个数超过1个的信号量称为计数信号量(counting semaphore),例如,有个8个资源,最大同时允许8个进程使用。

信号量编程步骤:

  • 1、生成 key,System V IPC的标识ID都是通过key来获取的,key的生成方式有三种。参考上一节消息队列编程步骤;
  • 2、使用int semget(key_t key, int nsems, int semflg);创建/获取信号量集,返回值为信号量集标识符。
    第二个参数nsems表示信号量集中信号量的个数。如果并非创建信号量, 仅仅是访问已经存在的信号量集, 可以将nsems指定为0。
    semflg支持多种标志位。 目前支持IPC_CREAT和IPC_EXCL标志位
  • 3、设置信号量的初始值 int semctl(int semid, int semnum, int cmd,/* union semun arg*/);
  • 4、正常使用,实现信号量的++ --的原子性int semop(int semid, struct sembuf *sops, unsigned nsops);
  • 5、semctl删除消息信号量
    semctl(semid, 0, IPC_RMID);

✨4.2 例子

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>// 生成key
#define SEM_KEY		10086int main()
{// 2 创建子进程pid_t pid = fork();if(pid == 0) {// 子进程printf("子进程[%d]开始执行, 创建信号量,使用资源\n", getpid());// 创建信号量集int semid = semget(SEM_KEY, 1, IPC_CREAT|0666);if(semid == -1){perror("semget failed");exit(1);}// 设置第0个信号量的资源数量为1if(semctl(semid, 0, SETVAL, 1) == -1){perror("semctl setval failed");exit(1);}// 使用资源,数量 -1struct sembuf op;op.sem_num = 0;//对下标为0的信号量操作op.sem_op = -1;//对信号量-1op.sem_flg = 0;//无法完成时阻塞等待semop(semid, &op, 1);printf("子进程[%d]访问共享资源\n", getpid());sleep(20);printf("子进程[%d]完成共享资源的访问\n",getpid());// 释放资源,数量 +1op.sem_op = 1;semop(semid, &op, 1);return 0;}else if(pid > 0)// 父进程{sleep(3); //延时一会,让子进程先运行printf("父进程[%d]开始执行, 获取信号量,准备使用资源\n", getpid()); int semid = semget(SEM_KEY, 0, 0);if(semid == -1){perror("semget failed");exit(1);}// 使用资源,数量 -1struct sembuf op;op.sem_num = 0;//对下标为0的信号量操作op.sem_op = -1;//对信号量-1op.sem_flg = 0;//无法完成时阻塞等待semop(semid, &op, 1);printf("父进程[%d]访问共享资源\n", getpid());sleep(3);printf("父进程[%d]完成共享资源的访问\n",getpid());// 释放资源,数量 +1op.sem_op = 1;semop(semid, &op, 1);// 删除信号量if(semctl(semid, 0, IPC_RMID) == -1){perror("semctl failed");exit(3);}printf("父进程[%d]退出\n", getpid());return 0;}else{printf("Error in fork\n"); exit(1); }return 0;
}

在这里插入图片描述

🎄五、共享内存(System V IPC)

✨5.1 共享内存(System V IPC)介绍

共享内存是所有IPC手段中最快的一种。 它之所以快是因为共享内存一旦映射到进程的地址空间,进程之间数据的传递就不须要涉及内核了。

建立共享内存之后, 进程从此就像操作普通进程的地址空间一样操作这块共享内存, 一个进程可以将信息写入这片内存区域, 而另一个进程也可以看到共享内存里面的信息, 从而达到通信的目的。

允许多个进程同时操作共享内存, 就不得不防范竞争条件的出现。因此, 共享内存这种进程间通信的手段通常不会单独出现, 总是和信号量、 文件锁等同步的手段配合使用。

信号量编程步骤:

  • 1、生成 key,System V IPC的标识ID都是通过key来获取的,key的生成方式有三种。参考上一节消息队列编程步骤;
  • 2、使用int shmget(key_t key, size_t size, int shmflg);创建/获取共享内存段,返回值为共享内存的标识符。
    其中第二个参数size必须是正整数, 表示要创建的共享内存的大小。
    第三个参数支持IPC_CREAT和IPC_EXCL标志位。 如果没有设置IPC_CREAT标志位, 那么第二个参数size对共享内存段并无实际意义, 但是必须小于或等于共享内存的大小, 否则会有EINVAL错误。
  • 3、映射共享内存,得到虚拟地址。void *shmat(int shmid, const void *shmaddr, int shmflg);
    其中, 第二个参数是用来指定将共享内存放到虚拟地址空间的什么位置的。 大部分的普通青年都会将第二个参数设置为NULL, 表示用户并不在意, 一切交由内核做主。
    shmat如果调用成功, 则返回进程虚拟地址空间内的一个地址。就可以像使用malloc分配的空间一样使用共享内存。
  • 4、读写共享内存数据。
  • 5、解除映射。int shmdt(const void *shmaddr);
  • 6、销毁共享内存。shmctl(shmid, IPC_RMID, NULL) ;

✨5.2 例子

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>// 生成key
#define SHM_KEY		10010int main()
{// 2 创建子进程pid_t pid = fork();if(pid == 0) {// 子进程printf("子进程[%d]开始执行, 创建共享内存段,使用创建共享内存\n", getpid());// 2.1 创建共享内存段int shmid = shmget(SHM_KEY, 8, IPC_CREAT|0666);if(shmid == -1){perror("semget failed");exit(1);}// 2.2 映射共享内存,得到虚拟地址void *p = shmat(shmid, 0, 0);if((void *)-1 == p){perror("shmat failed");exit(2);}// 2.3 读写共享内存int *pi = p;*pi = 0xaaaaaaaa;*(pi+1) = 0x55555555;printf("子进程[%d]写入%x, %x\n", getpid(), *pi, *(pi+1));// 2.4 解除映射if(shmdt(p) == -1){perror("shmdt failed");exit(3);}printf("子进程[%d]解除映射, 结束进程\n\n", getpid());return 0;}else if(pid > 0)// 父进程{sleep(3); //延时一会,让子进程先运行printf("父进程[%d]开始执行, 获取共享内存段,准备使用资源\n", getpid()); // 3.1 获取共享内存段int shmid = shmget(SHM_KEY, 0, 0);if(shmid == -1){perror("shmget failed");exit(1);}// 3.2 映射共享内存,得到虚拟地址void *p = shmat(shmid, 0, 0);if((void *)-1 == p){perror("shmat failed");exit(2);}// 3.3 读写共享内存int x = *((int *)p);int y = *((int *)p + 1);printf("父进程[%d]读取数据:x=%#x y=%#x\n",getpid(), x, y);// 3.4 解除映射if(shmdt(p) == -1){perror("shmdt failed");exit(3);}printf("父进程[%d]解除映射\n", getpid());// 3.5 销毁共享内存if(shmctl(shmid, IPC_RMID, NULL) == -1){perror("shmctl");exit(4);}printf("父进程[%d]销毁共享内存, 结束进程\n", getpid());return 0;}else{printf("Error in fork\n"); exit(1); }return 0;
}

允许结果:
在这里插入图片描述

在这里插入图片描述

🎄六、总结

Linux 进程间通信有10种方式,本文先介绍了5种:无名管道、命名管道、XSI消息队列、XSI信号量、XSI共享内存,下篇文章将会介绍剩下的5个方式:POSIX消息队列、POSIX信号量、POSIX共享内存、信号、网络通信。

Linux 进程间通信的10种方式(2)

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

相关文章:

【Linux C | 进程】Linux 进程间通信的10种方式(1)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…...

橘子学Mybatis08之Mybatis关于一级缓存的使用和适配器设计模式

前面我们说了mybatis的缓存设计体系&#xff0c;这里我们来正式看一下这玩意到底是咋个用法。 首先我们是知道的&#xff0c;Mybatis中存在两级缓存。分别是一级缓存(会话级)&#xff0c;和二级缓存(全局级)。 下面我们就来看看这两级缓存。 一、准备工作 1、准备数据库 在此之…...

看图说话:Git图谱解读

很多新加入公司的同学在使用Git各类客户端管理代码的过程中对于Git图谱解读不太理解&#xff0c;我们常用的Git客户端是SourceTree&#xff0c;配合P4Merge进行冲突解决基本可以满足日常工作大部分需要。不同的Git客户端工具对图谱展示会有些许差异&#xff0c;以下是SourceTre…...

linux新增用户,指定home目录和bash脚本且加入到sudoer列表

前言 近3年一直用自动化脚本&#xff0c;搞得连useradd命令都不会用了。哈哈。 今天还碰到一个问题&#xff0c;有个系统没有‘useradd’和‘passwd’命令&#xff0c;直接蒙了。当然直接用apt install就能安装&#xff0c;不然还得自己编译折腾一会。新建用户 useradd -d /h…...

经典目标检测YOLO系列(三)YOLOV3的复现(1)总体网络架构及前向处理过程

经典目标检测YOLO系列(三)YOLOV3的复现(1)总体网络架构及前向处理过程 和之前实现的YOLOv2一样&#xff0c;根据《YOLO目标检测》(ISBN:9787115627094)一书&#xff0c;在不脱离YOLOv3的大部分核心理念的前提下&#xff0c;重构一款较新的YOLOv3检测器&#xff0c;来对YOLOv3有…...

OpenGL/C++_学习笔记(四)空间概念与摄像头

汇总页 上一篇: OpenGL/C_学习笔记&#xff08;三&#xff09; 绘制第一个图形 OpenGL/C_学习笔记&#xff08;四&#xff09;空间概念与摄像头 空间概念与摄像头前置科技树: 线性代数空间概念流程简述各空间相关概念详述 空间概念与摄像头 前置科技树: 线性代数 矩阵/向量定…...

C语言2024-1-27练习记录

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>//int main() //{ // char c[15] { I, ,a,n,d, ,you,. }; // int i; // for(i 0; i < 15; i) //这个地方有几个地方需要注意一下&#xff0c;首先变量指定之后必须要加上英文状态下的分号 // printf("%c&q…...

深入解析HTTPS:安全机制全方位剖析

随着互联网的深入发展&#xff0c;网络传输中的数据安全性受到了前所未有的关注。HTTPS&#xff0c;作为HTTP的安全版本&#xff0c;为数据在客户端和服务器之间的传输提供了加密和身份验证&#xff0c;从而确保了数据的机密性、完整性和身份真实性。本文将详细探讨HTTPS背后的…...

【197】JAVA8调用阿里云对象存储API,保存图片并获取图片URL地址。

实际工作中&#xff0c;需要用阿里云对象存储保存图片&#xff0c;并且在上传图片到阿里云对象存储服务器后&#xff0c;获取图片在阿里云对象存储服务器的URL地址&#xff0c;以便给 WEB 前端显示。 阿里云对象存储上传图片的工具类 package zhangchao;import com.aliyun.os…...

2024.1.24 C++QT 作业

思维导图 练习题 1.提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数 #include <iostream> #include <string.h> #include <array> using namespace std;int main() {string str;cout << "…...

jenkins部署过程记录

一、jenkins部署git链接找不到 原因分析&#xff1a; 机器的git环境不是个人git的权限&#xff0c;所以clone不了。Jenkins的master节点部署机器已经部署较多其他的job在跑&#xff0c;如果直接修改机器的git配置&#xff0c;很可能影响到其他的job clone 不了代码&#xff0c…...

JS-策略设计模式

设计模式&#xff1a;针对特定问题提出的简洁优化的解决方案 一个问题有多种处理方案&#xff0c;而且处理方案随时可能增加或减少比如&#xff1a;商场满减活动 满50元减5元满100元减15元满200元减35元满500元减100元 // 满减金额计算函数 function count(money, type) {if …...

漏洞复现-EduSoho任意文件读取漏洞(附漏洞检测脚本)

免责声明 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…...

「QT」QString类的详细说明

✨博客主页何曾参静谧的博客📌文章专栏「QT」QT5程序设计📚全部专栏「VS」Visual Studio「C/C++」C/C++程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「...

微信小程序-04

rpx&#xff08;responsive pixel&#xff09;是微信小程序独有的&#xff0c;用来解决屏适配的尺寸单位。 import 后跟需要导入的外联样式表的相对路径&#xff0c;用 ; 表示语句结束。 定义在 app.wxss 中的样式为全局样式&#xff0c;作用于每一个页面。 在页面的 .wxss 文…...

什么是数据库的三级模式两级映象?

三级模式两级映象结构图 概念 三级模式 内模式&#xff1a;也称为存储模式&#xff0c;是数据物理结构和存储方式的描述&#xff0c;是数据在数据库内部的表示方式。定义所有的内部记录类型、索引和文件组织方式&#xff0c;以及数据控制方面的细节。模式&#xff1a;又称概念…...

初识人工智能,一文读懂机器学习之逻辑回归知识文集(6)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…...

2024 CKA 题库 | 15、备份还原 etcd

不等更新题库 文章目录 15、备份还原 etcd题目:考点&#xff1a;参考链接:解答:备份快照恢复快照 检查 15、备份还原 etcd 题目: 设置配置环境 此项目无需更改配置环境。但是&#xff0c;在执行此项目之前&#xff0c;请确保您已返回初始节点。 [candidatemaster01] $ exit #…...

基于Matlab/Simulink直驱式风电储能制氢仿真模型

接着还是以直驱式风电为DG中的研究对象&#xff0c;上篇博客考虑的风电并网惯性的问题&#xff0c;这边博客主要讨论功率消纳的问题。 考虑到风速是随机变化的&#xff0c;导致风电输出功率的波动性和间歇性问题突出&#xff1b;随着其应用规模的不断扩大以及风电在电网中渗透率…...

计算机网络(第六版)复习提纲16

三 IP地址与MAC地址 1 IP层只能看到IP数据报 2 路由器只根据目的IP地址进行转发 3 局域网的链路层只能看到MAC帧 4 IP层抽象的互联网屏蔽了下层的复杂细节&#xff0c;在网络层讨论问题能够使用统一的、抽象的IP地址来研究主机和主机或路由间的通信 问题&#xff1a; 1 主机或路…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...