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

Linux-进程间通信(IPC)

进程间通信(IPC)介绍

进程间通信(IPC,InterProcess Communication)是指在不同的进程之间传播或交换信息。IPC 的方式包括管道(无名管道和命名管道)、消息队列、信号量、共享内存、Socket、Streams 等。其中 Socket 和 Streams 支持不同主机上的两个进程间通信。

1. 管道

1.1 无名管道

1.1.1 特点
  • 它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。
  • 它只能用于父子进程之间的通信。
  • 管道是创建在内存中,进程结束空间释放,管道不复存在。对于它的读写可以使用普通的 readwrite 等函数。
1.1.2 函数原型
#include <unistd.h>
int pipe(int pipefd[2]);
1.1.3 返回值

成功返回 0,失败返回 -1。当一个管道建立时,它会创建两个文件描述符:fd[0] 为读而打开,fd[1] 为写而打开。

1.1.4 无名管道代码示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>int main() {int fd[2];int pid;char buf[128];if (pipe(fd) == -1) {printf("create pipe fail\n");}pid = fork();if (pid < 0) {printf("create child fail\n");} else if (pid > 0) {sleep(3);printf("this is father\n");close(fd[0]);write(fd[1], "hello from father", strlen("hello from father"));wait(NULL);} else {printf("this is child\n");close(fd[1]);read(fd[0], buf, 128);printf("read = %s \n", buf);exit(0);}return 0;
}

注意:管道的特性:管道里没有数据时会阻塞。

1.2 命名管道

1.2.1 特点
  • 命名管道可以在无关的进程之间交换数据,与无名管道不同。
  • 命名管道有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。
1.2.2 函数原型
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
1.2.3 命名管道代码示例

read.c

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main() {int fd;char buf[128] = {0};if (mkfifo("./file", 0600) == -1 && errno != EEXIST) {printf("mkfifo fail\n");perror("why");}fd = open("./file", O_RDONLY);printf("read open success\n");while (1) {int n_read = read(fd, buf, 128);printf("read %d byte, context = %s \n", n_read, buf);}close(fd);return 0;
}

write.c

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main() {int fd;char *str = "message from fifo";fd = open("./file", O_WRONLY);printf("write open success\n");while (1) {write(fd, str, strlen(str));sleep(1);}close(fd);return 0;
}

2. 消息队列

消息队列是信息的链接表,存放在内核中。一个消息队列由一个标识符(即队列 ID)来标识。

2.1 特点

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

2.2 函数原型

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>int msgget(key_t key, int msgflg);
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

2.3 消息队列代码示例

send.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>struct msgbuf {long mtype;char mtext[128];
};int main() {struct msgbuf sendBuf = {888, "this is msg from queue"};struct msgbuf readBuf;key_t key = ftok(".", 1);printf("key=%d\n", key);int msgId = msgget(key, IPC_CREAT | 0777);if (msgId == -1) {perror("why:");}while (1) {msgsnd(msgId, &sendBuf, strlen(sendBuf.mtext), 0);sleep(1);printf("write success\n");msgrcv(msgId, &readBuf, sizeof(readBuf.mtext), 988, 0);sleep(1);printf("read from queue: %s\n", readBuf.mtext);}msgctl(msgId, IPC_RMID, NULL);return 0;
}

read.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>struct msgbuf {long mtype;char mtext[128];
};int main() {struct msgbuf readBuf;struct msgbuf sendBuf = {988, "this is msg from father"};key_t key = ftok(".", 1);printf("key=%d\n", key);int msgId = msgget(key, IPC_CREAT | 0777);if (msgId == -1) {perror("why:");}while (1) {msgrcv(msgId, &readBuf, sizeof(readBuf.mtext), 888, 0);sleep(1);printf("read from queue: %s\n", readBuf.mtext);msgsnd(msgId, &sendBuf, strlen(sendBuf.mtext), 0);sleep(1);printf("write success\n");}msgctl(msgId, IPC_RMID, NULL);return 0;
}

3. 信号

3.1 信号的处理

信号的处理有三种方法:忽略、捕捉和默认动作。具体的信号默认动作可以使用 man 7 signal 来查看系统的具体定义。

3.2 信号处理函数的注册

信号处理函数的注册可以分为入门版和高级版:

  • 入门版:signal 函数
  • 高级版:sigaction 函数

3.3 信号处理发送函数

信号发送函数也分为入门版和高级版:

  • 入门版:kill
  • 高级版:sigqueue

3.4 signal 函数原型及示例

#include <signal.h>typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

示例

#include <signal.h>
#include <stdio.h>void handler(int signum) {printf("get signum = %d\n", signum);switch (signum) {case SIGINT:printf("SIGINT\n");break;case SIGKILL:printf("SIGKILL\n");break;case SIGUSR1:printf("SIGUSR1\n");break;}
}int main() {signal(SIGINT, handler);signal(SIGKILL, handler);signal(SIGUSR1, handler);while (1);return 0;
}

3.5 kill 函数原型及示例

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);

示例

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>int main(int argc, char **argv) {int signum = atoi(argv[1]);int pid = atoi(argv[2]);printf("signum = %d , pid = %d \n", signum, pid);kill(pid, signum);printf("send signal ok\n");return 0;
}

4. 信号量

信号量(semaphore)是一个计数器,用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。

4.1 特点

  • 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
  • 信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
  • 支持信号量组。

4.2 函数原型

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>int semget(key_t key, int nsems, int semflg);
int semop(int semid, struct sembuf *sops, unsigned nsops);
int semctl(int semid, int semnum, int cmd, ...);

4.3 信号量代码示例

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>//联合体,用于 semctl 初始化
union semun {int val;struct semid_ds *buf;unsigned short *array;
};void pGetKey(int id) {struct sembuf set;set.sem_num = 0;set.sem_op = -1;set.sem_flg = SEM_UNDO;semop(id, &set, 1);printf("get key\n");
}void pPutBackKey(int id) {struct sembuf set;set.sem_num = 0;set.sem_op = 1;set.sem_flg = SEM_UNDO;semop(id, &set, 1);printf("put back the key\n");
}int main() {int semid;key_t key = ftok(".", 2);//1. 获取或创建信号量semid = semget(key, 1, IPC_CREAT | 0666);union semun initsem;initsem.val = 0;//2. 初始化信号量semctl(semid, 0, SETVAL, initsem);int pid = fork();if (pid > 0) {//4. 拿锁pGetKey(semid);printf("this is father\n");//5. 还锁pPutBackKey(semid);//6. 销毁锁semctl(semid, 0, IPC_RMID);} else if (pid == 0) {printf("this is child\n");//3. 放锁pPutBackKey(semid);} else {printf("fork error\n");}return 0;
}

5. 共享内存

共享内存(shared memory)指两个或多个进程共享一个给定的存储区。

5.1 特点

  • 共享内存是最快的一种 IPC,因为进程是直接对内存进行存储,而不需要任何数据的拷贝。
  • 只能单独一个进程写或读,如果 A 和 B 进程同时写,会造成数据的混乱(需要搭配信号量来使用)。

5.2 函数原型

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

5.3 共享内存代码示例

shm_write.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>int main() {int shmid;char *shmaddr;key_t key = ftok(".", 1);// 创建共享内存shmid = shmget(key, 1024 * 4, IPC_CREAT | 0600);if (shmid == -1) {printf("create shm fail\n");exit(-1);}// 连接映射共享内存shmaddr = shmat(shmid, 0, 0);printf("shmat OK\n");// 将数据拷贝到共享内存strcpy(shmaddr, "hello world\n");sleep(5); // 等待 5 秒,避免一下子断开连接。等待另外一个进程读完。// 断开共享内存连接shmdt(shmaddr);// 删除共享内存shmctl(shmid, IPC_RMID, 0);printf("quit\n");return 0;
}

shm_get.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>int main() {int shmid;char *shmaddr;key_t key = ftok(".", 1);// 打开共享内存shmid = shmget(key, 1024 * 4, 0);if (shmid == -1) {printf("create shm fail\n");exit(-1);}// 连接并映射共享内存shmaddr = shmat(shmid, 0, 0);printf("get from shm_write message is: %s", shmaddr);// 断开共享内存连接shmdt(shmaddr);printf("quit\n");return 0;
}

6. 结合消息队列、共享内存、信号量的示例

6.1 代码示例

get.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include <string.h>// 消息队列结构
struct msg_form {long mtype;char mtext;
};// 联合体,用于 semctl 初始化
union semun {int val;struct semid_ds *buf;unsigned short *array;
};// 初始化信号量
int init_sem(int sem_id, int value) {union semun tmp;tmp.val = value;if (semctl(sem_id, 0, SETVAL, tmp) == -1) {perror("Init Semaphore Error");return -1;}return 0;
}// P 操作
int sem_p(int sem_id) {struct sembuf sbuf;sbuf.sem_num = 0;sbuf.sem_op = -1;sbuf.sem_flg = SEM_UNDO;if (semop(sem_id, &sbuf, 1) == -1) {perror("P operation Error");return -1;}return 0;
}// V 操作
int sem_v(int sem_id) {struct sembuf sbuf;sbuf.sem_num = 0;sbuf.sem_op = 1;sbuf.sem_flg = SEM_UNDO;if (semop(sem_id, &sbuf, 1) == -1) {perror("V operation Error");return -1;}return 0;
}// 删除信号量集
int del_sem(int sem_id) {union semun tmp;if (semctl(sem_id, 0, IPC_RMID, tmp) == -1) {perror("Delete Semaphore Error");return -1;}return 0;
}// 创建一个信号量集
int create_sem(key_t key) {int sem_id;if ((sem_id = semget(key, 1, IPC_CREAT | 0666)) == -1) {perror("semget error");exit(-1);}init_sem(sem_id, 1);  // 初值设为 1 资源未占用return sem_id;
}int main() {key_t key;int shmid, semid, msqid;char *shm;struct shmid_ds buf1;  // 用于删除共享内存struct msqid_ds buf2;  // 用于删除消息队列struct msg_form msg;   // 消息队列用于通知对方更新了共享内存// 获取 key 值if ((key = ftok(".", 'z')) < 0) {perror("ftok error");exit(1);}// 创建共享内存if ((shmid = shmget(key, 1024, IPC_CREAT | 0666)) == -1) {perror("Create Shared Memory Error");exit(1);}// 连接共享内存shm = (char *)shmat(shmid, 0, 0);if ((int)shm == -1) {perror("Attach Shared Memory Error");exit(1);}// 创建消息队列if ((msqid = msgget(key, IPC_CREAT | 0777)) == -1) {perror("msgget error");exit(1);}// 创建信号量semid = create_sem(key);// 读数据while (1) {msgrcv(msqid, &msg, 1, 888, 0);  // 读取类型为 888 的消息if (msg.mtext == 'q')  // quit - 跳出循环break;if (msg.mtext == 'r')  // read - 读共享内存{sem_p(semid);printf("%s\n", shm);sem_v(semid);}}// 断开连接shmdt(shm);// 删除共享内存、消息队列、信号量shmctl(shmid, IPC_RMID, &buf1);msgctl(msqid, IPC_RMID, &buf2);del_sem(semid);return 0;
}

send.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include <string.h>// 消息队列结构
struct msg_form {long mtype;char mtext;
};// 联合体,用于 semctl 初始化
union semun {int val;struct semid_ds *buf;unsigned short *array;
};// P 操作
int sem_p(int sem_id) {struct sembuf sbuf;sbuf.sem_num = 0;sbuf.sem_op = -1;sbuf.sem_flg = SEM_UNDO;if (semop(sem_id, &sbuf, 1) == -1) {perror("P operation Error");return -1;}return 0;
}// V 操作
int sem_v(int sem_id) {struct sembuf sbuf;sbuf.sem_num = 0;sbuf.sem_op = 1;sbuf.sem_flg = SEM_UNDO;if (semop(sem_id, &sbuf, 1) == -1) {perror("V operation Error");return -1;}return 0;
}int main() {key_t key;int shmid, semid, msqid;char *shm;struct msg_form msg;int flag = 1;  // while 循环条件// 获取 key 值if ((key = ftok(".", 'z')) < 0) {perror("ftok error");exit(1);}// 获取共享内存if ((shmid = shmget(key, 1024, 0)) == -1) {perror("shmget error");exit(1);}// 连接共享内存shm = (char *)shmat(shmid, 0, 0);if ((int)shm == -1) {perror("Attach Shared Memory Error");exit(1);}// 创建消息队列if ((msqid = msgget(key, 0)) == -1) {perror("msgget error");exit(1);}// 获取信号量if ((semid = semget(key, 0, 0)) == -1) {perror("semget error");exit(1);}// 写数据printf("***************************************\n");printf("*                 IPC                 *\n");printf("*    Input r to send data to server.  *\n");printf("*    Input q to quit.                 *\n");printf("***************************************\n");while (flag) {char c;printf("Please input command: ");scanf("%c", &c);switch (c) {case 'r':printf("Data to send: ");sem_p(semid);  // 访问资源scanf("%s", shm);sem_v(semid);  // 释放资源// 清空标准输入缓冲区while ((c = getchar()) != '\n' && c != EOF);msg.mtype = 888;msg.mtext = 'r';  // 发送消息通知服务器读数据msgsnd(msqid, &msg, sizeof(msg.mtext), 0);break;case 'q':msg.mtype = 888;msg.mtext = 'q';msgsnd(msqid, &msg, sizeof(msg.mtext), 0);flag = 0;break;default:printf("Wrong input!\n");// 清空标准输入缓冲区while ((c = getchar()) != '\n' && c != EOF);}}// 断开连接shmdt(shm);return 0;
}

7. 对比总结

通过上述对比可以看出,各种 IPC 方式各有优劣,选择合适的方式进行进程间通信可以提高程序的效率和可靠性。

相关文章:

Linux-进程间通信(IPC)

进程间通信&#xff08;IPC&#xff09;介绍 进程间通信&#xff08;IPC&#xff0c;InterProcess Communication&#xff09;是指在不同的进程之间传播或交换信息。IPC 的方式包括管道&#xff08;无名管道和命名管道&#xff09;、消息队列、信号量、共享内存、Socket、Stre…...

C++ STL: std::vector与std::array的深入对比

什么是 std::vector 和 std::array 首先&#xff0c;让我们简要介绍一下这两种容器&#xff1a; • std::vector&#xff1a;一个动态数组&#xff0c;可以根据需要动态调整其大小。 • std::array&#xff1a;一个固定大小的数组&#xff0c;其大小在编译时确定。 虽然…...

哈哈看到这条消息感觉就像是打开了窗户

在这个信息爆炸的时代&#xff0c;每一条动态可能成为我们情绪的小小触发器。今天&#xff0c;当我无意间滑过那条由杜海涛亲自发布的“自曝式”消息时&#xff0c;不禁心头一颤——如果这是我的另一半&#xff0c;哎呀&#xff0c;那画面&#xff0c;简直比烧烤摊还要“热辣”…...

10、matlab中字符、数字、矩阵、字符串和元胞合并为字符串并将字符串以不同格式写入读出excel

1、前言 在 MATLAB 中&#xff0c;可以使用不同的数据类型&#xff08;字符、数字、矩阵、字符串和元胞&#xff09;合并为字符串&#xff0c;然后将字符串以不同格式写入 Excel 文件。 以下是一个示例代码&#xff0c;展示如何将不同数据类型合并为字符串&#xff0c;并以不…...

如何正确面对GPT-5技术突破

随着人工智能技术的快速发展&#xff0c;预训练语言模型在自然语言处理领域取得了显著的成果。其中&#xff0c;GPT系列模型作为代表之一&#xff0c;受到了广泛关注。2023年&#xff0c;GPT-5模型的发布引起了业界的热烈讨论。本文将从以下几个方面分析GPT-5的发布及其对人工智…...

HarmonyOS ArkUi 官网踩坑:单独隐藏导航条无效

环境&#xff1a; 手机&#xff1a;Mate 60 Next版本&#xff1a; NEXT.0.0.26 导航条介绍 导航条官网设计指南 setSpecificSystemBarEnabled 设置实际效果&#xff1a; navigationIndicator&#xff1a;隐藏导航条无效status&#xff1a;会把导航条和状态栏都隐藏 官方…...

解决跨域问题(vite、axios/koa)

两种方法选其一即可 一、后端koa设置中间件 app.use(async (ctx, next)> {ctx.set(Access-Control-Allow-Origin, *);ctx.set(Access-Control-Allow-Headers, Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild);ctx.set(Access-C…...

echarts实现3D柱状图(视觉层面)

一、第一种效果 效果图 使用步骤 完整实例&#xff0c;copy就可直接使用 <template><div :class"className" :style"{height:height,width:width}" /> </template><script>import echarts from echartsrequire(echarts/theme/…...

K8S集群进行分布式负载测试

使用K8S集群执行分布式负载测试 本教程介绍如何使用Kubernetes部署分布式负载测试框架&#xff0c;该框架使用分布式部署的locust 产生压测流量&#xff0c;对一个部署到 K8S集群的 Web 应用执行负载测试&#xff0c;该 Web 应用公开了 REST 格式的端点&#xff0c;以响应传入…...

20.《C语言》——【移位操作符】

&#x1f339;开场语 亲爱的读者&#xff0c;大家好&#xff01;我是一名正在学习编程的高校生。在这个博客里&#xff0c;我将和大家一起探讨编程技巧、分享实用工具&#xff0c;并交流学习心得。希望通过我的博客&#xff0c;你能学到有用的知识&#xff0c;提高自己的技能&a…...

你想活出怎样的人生?

hi~好久不见&#xff0c;距离上次发文隔了有段时间了&#xff0c;这段时间&#xff0c;我是裸辞去感受了一下前端市场的水深火热&#xff0c;那么这次咱们不聊技术&#xff0c;就说一说最近这段时间的经历和一些感触吧。 先说一下自己的个人情况&#xff0c;目前做前端四年&am…...

py黑帽子学习笔记_burp

配置burp kali虚机默认装好了社区版burp和java&#xff0c;其他os需要手动装 burp是用java&#xff0c;还得下载一个jython包&#xff0c;供burp用 配apt国内源&#xff0c;然后apt install jython --download-only&#xff0c;会只下载包而不安装&#xff0c;下载的目录搜一…...

selenium,在元素块下查找条件元素

def get_norms_ele_text(self):elementsself.get_norms_elements()locBy.CSS_SELECTOR,"div.sku-select-row-label"by loc[0] # 获取By类型&#xff0c;例如By.CSS_SELECTORvalue loc[1] # 获取具体的CSS选择器字符串&#xff0c;例如"div.sku-select-row-l…...

认识String类

文章目录 String类字符串的遍历字符串的比较字符串的替换字符串的转换字符串的切割字符串的切片字符串的查找 总结 String类 在C语言中已经涉及到字符串了&#xff0c;但是在C语言中要表示字符串只能使用字符数组或者字符指针&#xff0c;可以使用标准库提 供的字符串系列函数完…...

计算机图形学入门23:蒙特卡洛路径追踪

1.前言 前面几篇文章介绍了Whitted-style光线追踪&#xff0c;还介绍了基于物理渲染的基础知识&#xff0c;包括辐射度量学、BRDF以及渲染方程&#xff0c;但并没有给出解渲染方程的方法&#xff0c;或者说如何通过该渲染方程计算出屏幕上每一个坐标的像素值。 Whitted-style光…...

探索 TensorFlow 模型的秘密:TensorBoard 详解与实战

简介 TensorBoard 是 TensorFlow 提供的可视化工具&#xff0c;帮助开发者监控和调试机器学习模型。它提供了多种功能&#xff0c;包括查看损失和精度曲线、可视化计算图、检查数据分布等。下面将介绍如何使用 TensorBoard。 1. 安装 TensorBoard 如果尚未安装 TensorBoard&…...

yolov8obb角度预测原理解析

预测头 ultralytics/nn/modules/head.py class OBB(Detect):"""YOLOv8 OBB detection head for detection with rotation models."""def __init__(self, nc80, ne1, ch()):"""Initialize OBB with number of classes nc and la…...

CICD之Git版本管理及基本应用

CICD:持续集成,持续交付--让对应的资料,对应的项目流程更加规范--提高效率 CICD 有很多的工具 GIT就是其中之一 1.版本控制概念与环境搭建 GIT的概念: Git是一款分布式源代码管理工具(版本控制工具) ,一个协同的工具。 Git得其数据更像是一系列微型文件系统的快照。使用Git&am…...

Python作用域及其应用

Python的作用域规则决定了变量在代码中的可见性和访问性。全局作用域中定义的变量可以在整个程序中访问&#xff0c;而局部作用域中定义的变量则只能在其被创建的函数或代码块中访问。 全局作用域与局部作用域 全局作用域中的变量通常在程序的顶层定义&#xff0c;可以被整个…...

谷歌上架,应用被Google play下架之后,活跃用户会暴跌?这是为什么?

在Google play上架应用&#xff0c;开发者们最不想到看到就是应用被下架了。这意味着所有的努力都将付诸东流&#xff0c;因为有的应用一但被下架&#xff0c;活跃用户也随之嗖嗖地往下掉&#xff0c;这事儿可真不是闹着玩的&#xff0c;严重影响了收益&#xff01; 为什么你的…...

web安全渗透测试十大常规项(一):web渗透测试之Fastjson反序列化

渗透测试之Java反序列化 1. Fastjson反序列化1.1 FastJson反序列化链知识点1.2 FastJson反序列化链分析1.3.1 FastJson 1.2.24 利用链分析1.3.2 FastJson 1.2.25-1.2.47 CC链分析1.3.2.1、开启autoTypeSupport:1.2.25-1.2.411.3.2.2 fastjson-1.2.42 版本绕过1.3.2.3 fastjson…...

Unity 3D软件下载安装;Unity 3D游戏制作软件资源包获取!

Unity3D&#xff0c;它凭借强大的功能和灵活的特性&#xff0c;在游戏开发和互动内容创作领域发挥着举足轻重的作用。 作为一款顶尖的游戏引擎&#xff0c;Unity3D内置了先进的物理引擎——PhysX。这一物理引擎堪称业界翘楚&#xff0c;能够为开发者提供全方位、高精度的物理模…...

PyTorch之nn.Module与nn.functional用法区别

文章目录 1. nn.Module2. nn.functional2.1 基本用法2.2 常用函数 3. nn.Module 与 nn.functional3.1 主要区别3.2 具体样例&#xff1a;nn.ReLU() 与 F.relu() 参考资料 1. nn.Module 在PyTorch中&#xff0c;nn.Module 类扮演着核心角色&#xff0c;它是构建任何自定义神经网…...

2024.06.24 校招 实习 内推 面经

绿*泡*泡VX&#xff1a; neituijunsir 交流*裙 &#xff0c;内推/实习/校招汇总表格 1、校招 | 昂瑞微2025届校园招聘正式启动 校招 | 昂瑞微2025届校园招聘正式启动 2、实习 | 东风公司研发总院暑期实习生火爆招募中 实习 | 东风公司研发总院暑期实习生火爆招募中 3、实习…...

【C++】using namespace std 到底什么意思

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文作为 JohnKi 的学习笔记&#xff0c;引用了部分大佬的案例 &#x1f4e2;未来很长&a…...

基于ESP32 IDF的WebServer实现以及OTA固件升级实现记录(三)

经过前面两篇的前序铺垫&#xff0c;对webserver以及restful api架构有了大体了解后本篇描述下最终的ota实现的代码以及调试中遇到的诡异bug。 eps32的实际ota实现过程其实esp32官方都已经基本实现好了&#xff0c;我们要做到无非就是把要升级的固件搬运到对应ota flash分区里面…...

116-基于5VLX110T FPGA FMC接口功能验证6U CPCI平台

一、板卡概述 本板卡是Xilinx公司芯片V5系列芯片设计信号处理板卡。由一片Xilinx公司的XC5VLX110T-1FF1136 / XC5VSX95T-1FF1136 / XC5VFX70T-1FF1136芯片组成。FPGA接1片DDR2内存条 2GB&#xff0c;32MB Nor flash存储器&#xff0c;用于存储程序。外扩 SATA、PCI、PCI expres…...

Android - Json/Gson

Json数据解析 json对象&#xff1a;花括号开头和结尾&#xff0c;中间是键值对形式————”属性”:属性值”” json数组&#xff1a;中括号里放置 json 数组&#xff0c;里面是多个json对象或者数字等 JSONObject 利用 JSONObject 解析 1.创建 JSONObject 对象&#xff0c;传…...

盲信号处理的发展现状

盲源分离技术最早在上个世纪中期提出&#xff0c;在1991年Herault和Jutten提出基于反馈神经网络的盲源分离方法&#xff0c;但该方法缺乏理论基础&#xff0c;后来Tong和Liu分析了盲源分离问题的可辨识性和不确定性&#xff0c;Cardoso于1993年提出了基于高阶统计的联合对角化盲…...

二轴机器人装箱机:重塑物流效率,精准灵活,引领未来装箱新潮流

在现代化物流领域&#xff0c;高效、精准与灵活性无疑是各大企业追求的核心目标。而在这个日益追求自动化的时代&#xff0c;二轴机器人装箱机凭借其较佳的性能和出色的表现&#xff0c;正逐渐成为装箱作业的得力助手&#xff0c;引领着未来装箱新潮流。 一、高效&#xff1a;重…...